--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -512,16 +512,18 @@ using mozilla::dom::indexedDB::IDBWrappe
#include "Telephony.h"
#include "TelephonyCall.h"
#include "CallEvent.h"
#endif
#ifdef MOZ_B2G_BT
#include "BluetoothManager.h"
#include "BluetoothAdapter.h"
+#include "BluetoothDevice.h"
+#include "BluetoothDeviceEvent.h"
#endif
#include "nsIDOMNavigatorSystemMessages.h"
#include "DOMError.h"
#include "DOMRequest.h"
#include "nsIOpenWindowEventDetail.h"
#include "nsIDOMGlobalObjectConstructor.h"
@@ -1666,17 +1668,21 @@ static nsDOMClassInfoData sClassInfoData
NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif
#ifdef MOZ_B2G_BT
NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
+ EVENTTARGET_SCRIPTABLE_FLAGS)
+ NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
+ NS_DEFINE_CLASSINFO_DATA(BluetoothDeviceEvent, nsDOMGenericSH,
+ DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif
NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(OpenWindowEventDetail, nsDOMGenericSH,
@@ -4479,16 +4485,25 @@ nsDOMClassInfo::Init()
#ifdef MOZ_B2G_BT
DOM_CLASSINFO_MAP_BEGIN(BluetoothManager, nsIDOMBluetoothManager)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothManager)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
DOM_CLASSINFO_MAP_END
+
+ DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
+ DOM_CLASSINFO_MAP_END
+
+ DOM_CLASSINFO_MAP_BEGIN(BluetoothDeviceEvent, nsIDOMBluetoothDeviceEvent)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDeviceEvent)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
+ DOM_CLASSINFO_MAP_END
#endif
DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DOMRequest, nsIDOMDOMRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -523,16 +523,18 @@ DOMCI_CLASS(MozWifiConnectionInfoEvent)
DOMCI_CLASS(Telephony)
DOMCI_CLASS(TelephonyCall)
DOMCI_CLASS(CallEvent)
#endif
#ifdef MOZ_B2G_BT
DOMCI_CLASS(BluetoothManager)
DOMCI_CLASS(BluetoothAdapter)
+DOMCI_CLASS(BluetoothDevice)
+DOMCI_CLASS(BluetoothDeviceEvent)
#endif
DOMCI_CLASS(DOMError)
DOMCI_CLASS(DOMRequest)
DOMCI_CLASS(OpenWindowEventDetail)
DOMCI_CLASS(DOMFileHandle)
DOMCI_CLASS(FileRequest)
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -1,64 +1,277 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "base/basictypes.h"
#include "BluetoothAdapter.h"
-#include "BluetoothUtils.h"
+#include "BluetoothDevice.h"
+#include "BluetoothDeviceEvent.h"
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
#include "nsDOMClassInfo.h"
#include "nsDOMEvent.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCIDInternal.h"
+#include "nsIDOMDOMRequest.h"
+
#include "mozilla/LazyIdleThread.h"
#include "mozilla/Util.h"
+using namespace mozilla;
+
USING_BLUETOOTH_NAMESPACE
DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter,
nsDOMEventTargetHelper)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicefound)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicedisappeared)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter,
nsDOMEventTargetHelper)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicefound)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicedisappeared)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
-BluetoothAdapter::BluetoothAdapter(const nsCString& name) :
- mName(name)
+class GetPropertiesTask : public BluetoothReplyRunnable
{
-}
+public:
+ GetPropertiesTask(BluetoothAdapter* aAdapter, nsIDOMDOMRequest* aReq) :
+ BluetoothReplyRunnable(aReq),
+ mAdapterPtr(aAdapter)
+ {
+ }
+
+ bool
+ ParseSuccessfulReply(jsval* aValue)
+ {
+ const InfallibleTArray<BluetoothNamedValue>& values =
+ mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
+ for (uint32_t i = 0; i < values.Length(); ++i) {
+ mAdapterPtr->SetPropertyByValue(values[i]);
+ }
+ *aValue = JSVAL_VOID;
+ return true;
+ }
+
+ void
+ ReleaseMembers()
+ {
+ BluetoothReplyRunnable::ReleaseMembers();
+ mAdapterPtr = nsnull;
+ }
+private:
+ nsRefPtr<BluetoothAdapter> mAdapterPtr;
+};
BluetoothAdapter::~BluetoothAdapter()
{
- if (NS_FAILED(UnregisterBluetoothEventHandler(mName, this))) {
- NS_WARNING("Failed to unregister object with observer!");
+ BluetoothService* bs = BluetoothService::Get();
+ // We can be null on shutdown, where this might happen
+ if (bs) {
+ if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) {
+ NS_WARNING("Failed to unregister object with observer!");
+ }
+ }
+}
+
+void
+BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
+{
+ const nsString& name = aValue.name();
+ const BluetoothValue& value = aValue.value();
+ if (name.EqualsLiteral("Name")) {
+ mName = value.get_nsString();
+ } else if (name.EqualsLiteral("Address")) {
+ mAddress = value.get_nsString();
+ } else if (name.EqualsLiteral("Enabled")) {
+ mEnabled = value.get_bool();
+ } else if (name.EqualsLiteral("Discoverable")) {
+ mDiscoverable = value.get_bool();
+ } else if (name.EqualsLiteral("Pairable")) {
+ mPairable = value.get_bool();
+ } else if (name.EqualsLiteral("Powered")) {
+ mPowered = value.get_bool();
+ } else if (name.EqualsLiteral("PairableTimeout")) {
+ mPairableTimeout = value.get_uint32_t();
+ } else if (name.EqualsLiteral("DiscoverableTimeout")) {
+ mDiscoverableTimeout = value.get_uint32_t();
+ } else if (name.EqualsLiteral("Class")) {
+ mClass = value.get_uint32_t();
+ } else if (name.EqualsLiteral("UUIDs")) {
+ mUuids = value.get_ArrayOfnsString();
+ } else {
+#ifdef DEBUG
+ nsCString warningMsg;
+ warningMsg.AssignLiteral("Not handling adapter property: ");
+ warningMsg.Append(NS_ConvertUTF16toUTF8(name));
+ NS_WARNING(warningMsg.get());
+#endif
}
}
// static
already_AddRefed<BluetoothAdapter>
-BluetoothAdapter::Create(const nsCString& name) {
- nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(name);
- if (NS_FAILED(RegisterBluetoothEventHandler(name, adapter))) {
+BluetoothAdapter::Create(nsPIDOMWindow* aOwner, const nsAString& aPath)
+{
+ // Make sure we at least have a path
+ NS_ASSERTION(!aPath.IsEmpty(), "Adapter created with empty path!");
+
+ BluetoothService* bs = BluetoothService::Get();
+ MOZ_ASSERT(bs);
+
+ nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aPath);
+ adapter->BindToOwner(aOwner);
+ if (NS_FAILED(bs->RegisterBluetoothSignalHandler(aPath, adapter))) {
NS_WARNING("Failed to register object with observer!");
- return NULL;
+ return nsnull;
}
return adapter.forget();
}
-void BluetoothAdapter::Notify(const BluetoothEvent& aData) {
- printf("Got an adapter message!\n");
+void
+BluetoothAdapter::Notify(const BluetoothSignal& aData)
+{
+ if (aData.name().EqualsLiteral("DeviceFound")) {
+ nsRefPtr<BluetoothDevice> d = BluetoothDevice::Create(GetOwner(), aData);
+ nsRefPtr<BluetoothDeviceEvent> e = BluetoothDeviceEvent::Create(d);
+ e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("devicefound"));
+ } else {
+#ifdef DEBUG
+ nsCString warningMsg;
+ warningMsg.AssignLiteral("Not handling manager signal: ");
+ warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
+ NS_WARNING(warningMsg.get());
+#endif
+ }
+}
+
+nsresult
+BluetoothAdapter::StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest)
+{
+ BluetoothService* bs = BluetoothService::Get();
+ MOZ_ASSERT(bs);
+
+ nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+
+ if (!rs) {
+ NS_WARNING("No DOMRequest Service!");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsIDOMDOMRequest> req;
+ nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Can't create DOMRequest!");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
+
+ if (aStart) {
+ rv = bs->StartDiscoveryInternal(mPath, results);
+ } else {
+ rv = bs->StopDiscoveryInternal(mPath, results);
+ }
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Starting discovery failed!");
+ return NS_ERROR_FAILURE;
+ }
+
+ req.forget(aRequest);
+
+ // mDiscovering is not set here, we'll get a Property update from our external
+ // protocol to tell us that it's been set.
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::StartDiscovery(nsIDOMDOMRequest** aRequest)
+{
+ return StartStopDiscovery(true, aRequest);
}
+
+NS_IMETHODIMP
+BluetoothAdapter::StopDiscovery(nsIDOMDOMRequest** aRequest)
+{
+ return StartStopDiscovery(false, aRequest);
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetEnabled(bool* aEnabled)
+{
+ *aEnabled = mEnabled;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetAddress(nsAString& aAddress)
+{
+ aAddress = mAddress;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetAdapterClass(PRUint32* aClass)
+{
+ *aClass = mClass;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDiscovering(bool* aDiscovering)
+{
+ *aDiscovering = mDiscovering;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetName(nsAString& aName)
+{
+ aName = mName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDiscoverable(bool* aDiscoverable)
+{
+ *aDiscoverable = mDiscoverable;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDiscoverableTimeout(PRUint32* aDiscoverableTimeout)
+{
+ *aDiscoverableTimeout = mDiscoverableTimeout;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices)
+{
+ NS_WARNING("GetDevices not yet implemented.");
+ return NS_OK;
+}
+
+NS_IMPL_EVENT_HANDLER(BluetoothAdapter, propertychanged)
+NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicefound)
+NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicedisappeared)
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -3,45 +3,86 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluetoothadapter_h__
#define mozilla_dom_bluetooth_bluetoothadapter_h__
#include "BluetoothCommon.h"
+#include "nsCOMPtr.h"
#include "nsDOMEventTargetHelper.h"
#include "nsIDOMBluetoothAdapter.h"
-#include "nsIDOMDOMRequest.h"
-#include "mozilla/Observer.h"
class nsIEventTarget;
+class nsIDOMDOMRequest;
BEGIN_BLUETOOTH_NAMESPACE
+class BluetoothSignal;
+class BluetoothNamedValue;
+
class BluetoothAdapter : public nsDOMEventTargetHelper
, public nsIDOMBluetoothAdapter
- , public BluetoothEventObserver
+ , public BluetoothSignalObserver
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMBLUETOOTHADAPTER
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothAdapter,
nsDOMEventTargetHelper)
+ static already_AddRefed<BluetoothAdapter>
+ Create(nsPIDOMWindow* aOwner, const nsAString& name);
- static already_AddRefed<BluetoothAdapter>
- Create(const nsCString& name);
+ void Notify(const BluetoothSignal& aParam);
+
+ nsIDOMEventTarget*
+ ToIDOMEventTarget() const
+ {
+ return static_cast<nsDOMEventTargetHelper*>(
+ const_cast<BluetoothAdapter*>(this));
+ }
+
+ nsISupports*
+ ToISupports() const
+ {
+ return ToIDOMEventTarget();
+ }
- void Notify(const BluetoothEvent& aParam);
-protected:
- nsCString mName;
+ nsresult GetProperties();
+ void SetPropertyByValue(const BluetoothNamedValue& aValue);
private:
- BluetoothAdapter() {}
- BluetoothAdapter(const nsCString& name);
+
+ BluetoothAdapter(const nsAString& aPath) : mPath(aPath)
+ {
+ }
+
~BluetoothAdapter();
+
+ nsresult SetProperty(const BluetoothNamedValue& aValue,
+ nsIDOMDOMRequest** aRequest);
+ nsresult StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest);
+
+ nsString mAddress;
+ nsString mName;
+ nsString mPath;
+ bool mEnabled;
+ bool mDiscoverable;
+ bool mDiscovering;
+ bool mPairable;
+ bool mPowered;
+ PRUint32 mPairableTimeout;
+ PRUint32 mDiscoverableTimeout;
+ PRUint32 mClass;
+ nsTArray<nsString> mDeviceAddresses;
+ nsTArray<nsString> mUuids;
+
+ NS_DECL_EVENT_HANDLER(propertychanged)
+ NS_DECL_EVENT_HANDLER(devicefound)
+ NS_DECL_EVENT_HANDLER(devicedisappeared)
};
END_BLUETOOTH_NAMESPACE
#endif
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -17,49 +17,14 @@
} /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */
#define USING_BLUETOOTH_NAMESPACE \
using namespace mozilla::dom::bluetooth;
class nsCString;
BEGIN_BLUETOOTH_NAMESPACE
-/**
- * BluetoothEvents usually hand back one of 3 types:
- *
- * - 32-bit Int
- * - String
- * - Bool
- *
- * BluetoothVariant encases the types into a single structure.
- */
-struct BluetoothVariant
-{
- uint32_t mUint32;
- nsCString mString;
-};
-
-/**
- * BluetoothNamedVariant is a variant with a name value, for passing around
- * things like properties with variant values.
- */
-struct BluetoothNamedVariant
-{
- nsCString mName;
- BluetoothVariant mValue;
-};
-
-/**
- * BluetoothEvent holds a variant value and the name of an event, such as
- * PropertyChanged or DeviceFound.
- */
-struct BluetoothEvent
-{
- nsCString mEventName;
- nsTArray<BluetoothNamedVariant> mValues;
-};
-
-typedef mozilla::Observer<BluetoothEvent> BluetoothEventObserver;
-typedef mozilla::ObserverList<BluetoothEvent> BluetoothEventObserverList;
+class BluetoothSignal;
+typedef mozilla::Observer<BluetoothSignal> BluetoothSignalObserver;
END_BLUETOOTH_NAMESPACE
#endif // mozilla_dom_bluetooth_bluetoothcommon_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -0,0 +1,117 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+#include "BluetoothDevice.h"
+#include "BluetoothTypes.h"
+
+#include "nsDOMClassInfo.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+DOMCI_DATA(BluetoothDevice, BluetoothDevice)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
+ nsDOMEventTargetHelper)
+ NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
+ nsDOMEventTargetHelper)
+ NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDevice)
+ NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDevice)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
+
+BluetoothDevice::BluetoothDevice(const BluetoothSignal& aSignal)
+{
+ const InfallibleTArray<BluetoothNamedValue>& values =
+ aSignal.value().get_ArrayOfBluetoothNamedValue();
+ for (uint32_t i = 0; i < values.Length(); ++i) {
+ SetPropertyByValue(values[i]);
+ }
+}
+
+void
+BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
+{
+ const nsString& name = aValue.name();
+ const BluetoothValue& value = aValue.value();
+ if (name.EqualsLiteral("Name")) {
+ mName = value.get_nsString();
+ } else if (name.EqualsLiteral("Address")) {
+ mAddress = value.get_nsString();
+ } else if (name.EqualsLiteral("Class")) {
+ mClass = value.get_uint32_t();
+ } else if (name.EqualsLiteral("Connected")) {
+ mConnected = value.get_bool();
+ } else if (name.EqualsLiteral("Paired")) {
+ mPaired = value.get_bool();
+ } else if (name.EqualsLiteral("UUIDs")) {
+ mUuids = value.get_ArrayOfnsString();
+ } else {
+#ifdef DEBUG
+ nsCString warningMsg;
+ warningMsg.AssignLiteral("Not handling device property: ");
+ warningMsg.Append(NS_ConvertUTF16toUTF8(name));
+ NS_WARNING(warningMsg.get());
+#endif
+ }
+}
+
+// static
+already_AddRefed<BluetoothDevice>
+BluetoothDevice::Create(nsPIDOMWindow* aOwner, const BluetoothSignal& aSignal)
+{
+ nsRefPtr<BluetoothDevice> device = new BluetoothDevice(aSignal);
+ device->BindToOwner(device);
+ return device.forget();
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetAddress(nsAString& aAddress)
+{
+ aAddress = mAddress;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetName(nsAString& aName)
+{
+ aName = mName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetDeviceClass(PRUint32* aClass)
+{
+ *aClass = mClass;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetPaired(bool* aPaired)
+{
+ *aPaired = mPaired;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetConnected(bool* aConnected)
+{
+ *aConnected = mConnected;
+ return NS_OK;
+}
+
+NS_IMPL_EVENT_HANDLER(BluetoothDevice, propertychanged)
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDevice.h
@@ -0,0 +1,65 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothdevice_h__
+#define mozilla_dom_bluetooth_bluetoothdevice_h__
+
+#include "BluetoothCommon.h"
+#include "nsDOMEventTargetHelper.h"
+#include "nsIDOMBluetoothDevice.h"
+#include "nsString.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothNamedValue;
+class BluetoothSignal;
+
+class BluetoothDevice : public nsDOMEventTargetHelper
+ , public nsIDOMBluetoothDevice
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIDOMBLUETOOTHDEVICE
+
+ NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
+
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDevice,
+ nsDOMEventTargetHelper)
+
+ static already_AddRefed<BluetoothDevice>
+ Create(nsPIDOMWindow* aOwner, const BluetoothSignal& aSignal);
+
+ nsIDOMEventTarget*
+ ToIDOMEventTarget() const
+ {
+ return static_cast<nsDOMEventTargetHelper*>(
+ const_cast<BluetoothDevice*>(this));
+ }
+
+ nsISupports*
+ ToISupports() const
+ {
+ return ToIDOMEventTarget();
+ }
+
+private:
+ BluetoothDevice(const BluetoothSignal& aSignal);
+ ~BluetoothDevice() {}
+ void SetPropertyByValue(const BluetoothNamedValue& aValue);
+
+ nsString mAddress;
+ nsString mName;
+ PRUint32 mClass;
+ bool mConnected;
+ bool mPaired;
+ nsTArray<nsString> mUuids;
+
+ NS_DECL_EVENT_HANDLER(propertychanged)
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDeviceEvent.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+#include "BluetoothDeviceEvent.h"
+#include "BluetoothTypes.h"
+#include "BluetoothDevice.h"
+
+#include "nsDOMClassInfo.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+// static
+already_AddRefed<BluetoothDeviceEvent>
+BluetoothDeviceEvent::Create(BluetoothDevice* aDevice)
+{
+ NS_ASSERTION(aDevice, "Null pointer!");
+
+ nsRefPtr<BluetoothDeviceEvent> event = new BluetoothDeviceEvent();
+
+ event->mDevice = aDevice;
+
+ return event.forget();
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDeviceEvent)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDeviceEvent,
+ nsDOMEvent)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDevice)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDeviceEvent,
+ nsDOMEvent)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDevice)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDeviceEvent)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDeviceEvent)
+ NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDeviceEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(BluetoothDeviceEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(BluetoothDeviceEvent, nsDOMEvent)
+
+DOMCI_DATA(BluetoothDeviceEvent, BluetoothDeviceEvent)
+
+NS_IMETHODIMP
+BluetoothDeviceEvent::GetDevice(nsIDOMBluetoothDevice** aDevice)
+{
+ nsCOMPtr<nsIDOMBluetoothDevice> device = mDevice.get();
+ device.forget(aDevice);
+ return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDeviceEvent.h
@@ -0,0 +1,68 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_deviceevent_h__
+#define mozilla_dom_bluetooth_deviceevent_h__
+
+#include "BluetoothCommon.h"
+
+#include "nsIDOMBluetoothDeviceEvent.h"
+#include "nsIDOMEventTarget.h"
+
+#include "nsDOMEvent.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothDevice;
+
+class BluetoothDeviceEvent : public nsDOMEvent
+ , public nsIDOMBluetoothDeviceEvent
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_FORWARD_TO_NSDOMEVENT
+ NS_DECL_NSIDOMBLUETOOTHDEVICEEVENT
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDeviceEvent, nsDOMEvent)
+
+ static already_AddRefed<BluetoothDeviceEvent>
+ Create(BluetoothDevice* aDevice);
+
+ nsresult
+ Dispatch(nsIDOMEventTarget* aTarget, const nsAString& aEventType)
+ {
+ NS_ASSERTION(aTarget, "Null pointer!");
+ NS_ASSERTION(!aEventType.IsEmpty(), "Empty event type!");
+
+ nsresult rv = InitEvent(aEventType, false, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = SetTrusted(true);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIDOMEvent* thisEvent =
+ static_cast<nsDOMEvent*>(const_cast<BluetoothDeviceEvent*>(this));
+
+ bool dummy;
+ rv = aTarget->DispatchEvent(thisEvent, &dummy);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+ }
+
+private:
+ BluetoothDeviceEvent()
+ : nsDOMEvent(nsnull, nsnull)
+ { }
+
+ ~BluetoothDeviceEvent()
+ { }
+
+ nsCOMPtr<nsIDOMBluetoothDevice> mDevice;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
deleted file mode 100644
--- a/dom/bluetooth/BluetoothFirmware.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=40: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "BluetoothFirmware.h"
-
-#include "nsDebug.h"
-#include "nsError.h"
-#include <dlfcn.h>
-
-namespace mozilla {
-namespace dom {
-namespace bluetooth {
-
-static struct BluedroidFunctions {
- bool initialized;
- bool tried_initialization;
-
- BluedroidFunctions() :
- initialized(false),
- tried_initialization(false)
- {
- }
-
- int (* bt_enable)();
- int (* bt_disable)();
- int (* bt_is_enabled)();
-} sBluedroidFunctions;
-
-bool EnsureBluetoothInit() {
- if (sBluedroidFunctions.tried_initialization)
- {
- return sBluedroidFunctions.initialized;
- }
-
- sBluedroidFunctions.initialized = false;
- sBluedroidFunctions.tried_initialization = true;
-
- void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
-
- if(!handle) {
- NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
- return false;
- }
-
- sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
- if(sBluedroidFunctions.bt_enable == NULL) {
- NS_ERROR("Failed to attach bt_enable function");
- return false;
- }
- sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
- if(sBluedroidFunctions.bt_disable == NULL) {
- NS_ERROR("Failed to attach bt_disable function");
- return false;
- }
- sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
- if(sBluedroidFunctions.bt_is_enabled == NULL) {
- NS_ERROR("Failed to attach bt_is_enabled function");
- return false;
- }
- sBluedroidFunctions.initialized = true;
- return true;
-}
-
-int IsBluetoothEnabled()
-{
- return sBluedroidFunctions.bt_is_enabled();
-}
-
-int EnableBluetooth()
-{
- return sBluedroidFunctions.bt_enable();
-}
-
-int DisableBluetooth()
-{
- return sBluedroidFunctions.bt_disable();
-}
-
-
-}
-}
-}
deleted file mode 100644
--- a/dom/bluetooth/BluetoothFirmware.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=40: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_bluetoothfirmware_h__
-#define mozilla_dom_bluetooth_bluetoothfirmware_h__
-
-namespace mozilla {
-namespace dom {
-namespace bluetooth {
-
-bool EnsureBluetoothInit();
-int IsBluetoothEnabled();
-int EnableBluetooth();
-int DisableBluetooth();
-
-}
-}
-}
-
-#endif
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -1,281 +1,285 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "base/basictypes.h"
#include "BluetoothManager.h"
#include "BluetoothCommon.h"
-#include "BluetoothFirmware.h"
#include "BluetoothAdapter.h"
-#include "BluetoothUtils.h"
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
-#include "nsIURI.h"
-#include "nsIURL.h"
-#include "nsPIDOMWindow.h"
-
-#include "jsapi.h"
+#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
+#include "nsIDOMDOMRequest.h"
#include "nsDOMClassInfo.h"
#include "nsDOMEvent.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCIDInternal.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/Util.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsContentUtils.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsNetUtil.h"
-#include "nsServiceManagerUtils.h"
#define DOM_BLUETOOTH_URL_PREF "dom.mozBluetooth.whitelist"
using namespace mozilla;
using mozilla::Preferences;
USING_BLUETOOTH_NAMESPACE
-static void
-FireEnabled(bool aResult, nsIDOMDOMRequest* aDomRequest)
-{
- nsCOMPtr<nsIDOMRequestService> rs =
- do_GetService("@mozilla.org/dom/dom-request-service;1");
-
- if (!rs) {
- NS_WARNING("No DOMRequest Service!");
- return;
- }
-
- DebugOnly<nsresult> rv =
- aResult ?
- rs->FireSuccess(aDomRequest, JSVAL_VOID) :
- rs->FireError(aDomRequest,
- NS_LITERAL_STRING("Bluetooth firmware loading failed"));
-
- NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Bluetooth firmware loading failed");
-}
-
DOMCI_DATA(BluetoothManager, BluetoothManager)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothManager)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothManager,
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothManager,
nsDOMEventTargetHelper)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(enabled)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothManager,
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothManager,
nsDOMEventTargetHelper)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(enabled)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothManager)
NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothManager)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothManager)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(BluetoothManager, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(BluetoothManager, nsDOMEventTargetHelper)
-class ToggleBtResultTask : public nsRunnable
+class GetAdapterTask : public BluetoothReplyRunnable
{
- public:
- ToggleBtResultTask(nsRefPtr<BluetoothManager>& aManager,
- nsCOMPtr<nsIDOMDOMRequest>& aReq,
- bool aEnabled,
- bool aResult)
- : mEnabled(aEnabled),
- mResult(aResult)
- {
- MOZ_ASSERT(!NS_IsMainThread());
+public:
+ GetAdapterTask(BluetoothManager* aManager,
+ nsIDOMDOMRequest* aReq) :
+ BluetoothReplyRunnable(aReq),
+ mManagerPtr(aManager)
+ {
+ }
- mDOMRequest.swap(aReq);
- mManagerPtr.swap(aManager);
+ bool
+ ParseSuccessfulReply(jsval* aValue)
+ {
+ nsCOMPtr<nsIDOMBluetoothAdapter> adapter;
+ *aValue = JSVAL_VOID;
+
+ const nsString& path =
+ mReply->get_BluetoothReplySuccess().value().get_nsString();
+ adapter = BluetoothAdapter::Create(mManagerPtr->GetOwner(),
+ path);
+
+ nsresult rv;
+ nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv);
+ if (!sc) {
+ NS_WARNING("Cannot create script context!");
+ SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
+ return false;
}
- NS_IMETHOD Run()
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- // Update bt power status to BluetoothAdapter only if loading bluetooth
- // firmware succeeds.
- if (mResult) {
- mManagerPtr->SetEnabledInternal(mEnabled);
- }
-
- FireEnabled(mResult, mDOMRequest);
-
- //mAdapterPtr must be null before returning to prevent the background
- //thread from racing to release it during the destruction of this runnable.
- mManagerPtr = NULL;
- mDOMRequest = NULL;
-
- return NS_OK;
+ rv = nsContentUtils::WrapNative(sc->GetNativeContext(),
+ sc->GetNativeGlobal(),
+ adapter,
+ aValue);
+ bool result = NS_SUCCEEDED(rv) ? true : false;
+ if (!result) {
+ NS_WARNING("Cannot create native object!");
+ SetError(NS_LITERAL_STRING("BluetoothNativeObjectError"));
}
- private:
- nsRefPtr<BluetoothManager> mManagerPtr;
- nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
- bool mEnabled;
- bool mResult;
+ return result;
+ }
+
+ void
+ ReleaseMembers()
+ {
+ BluetoothReplyRunnable::ReleaseMembers();
+ mManagerPtr = nsnull;
+ }
+
+private:
+ nsRefPtr<BluetoothManager> mManagerPtr;
};
-class ToggleBtTask : public nsRunnable
+class ToggleBtResultTask : public BluetoothReplyRunnable
{
- public:
- ToggleBtTask(bool aEnabled, nsIDOMDOMRequest* aReq,
- BluetoothManager* aManager)
- : mEnabled(aEnabled),
- mManagerPtr(aManager),
- mDOMRequest(aReq)
- {
- MOZ_ASSERT(NS_IsMainThread());
- }
-
- NS_IMETHOD Run()
- {
- MOZ_ASSERT(!NS_IsMainThread());
-
- bool result;
-
-#ifdef MOZ_WIDGET_GONK
- // Platform specific check for gonk until object is divided in
- // different implementations per platform. Linux doesn't require
- // bluetooth firmware loading, but code should work otherwise.
- if(!EnsureBluetoothInit()) {
- NS_ERROR("Failed to load bluedroid library.\n");
- return NS_ERROR_FAILURE;
- }
+public:
+ ToggleBtResultTask(BluetoothManager* aManager,
+ nsIDOMDOMRequest* aReq,
+ bool aEnabled)
+ : BluetoothReplyRunnable(aReq),
+ mManagerPtr(aManager),
+ mEnabled(aEnabled)
+ {
+ }
- // return 1 if it's enabled, 0 if it's disabled, and -1 on error
- int isEnabled = IsBluetoothEnabled();
+ ~ToggleBtResultTask()
+ {
+ }
+
+ bool
+ ParseSuccessfulReply(jsval* aValue)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ *aValue = JSVAL_VOID;
+ mManagerPtr->SetEnabledInternal(mEnabled);
+ return true;
+ }
- if ((isEnabled == 1 && mEnabled) || (isEnabled == 0 && !mEnabled)) {
- result = true;
- } else if (isEnabled < 0) {
- result = false;
- } else if (mEnabled) {
- result = (EnableBluetooth() == 0) ? true : false;
- } else {
- result = (DisableBluetooth() == 0) ? true : false;
- }
-#else
- result = true;
- NS_WARNING("No bluetooth firmware loading support in this build configuration, faking a success event instead");
-#endif
-
- // Create a result thread and pass it to Main Thread,
- nsCOMPtr<nsIRunnable> resultRunnable = new ToggleBtResultTask(mManagerPtr, mDOMRequest, mEnabled, result);
-
- if (NS_FAILED(NS_DispatchToMainThread(resultRunnable))) {
- NS_WARNING("Failed to dispatch to main thread!");
- }
-
- return NS_OK;
- }
-
- private:
- bool mEnabled;
- nsRefPtr<BluetoothManager> mManagerPtr;
- nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
+ void
+ ReleaseMembers()
+ {
+ BluetoothReplyRunnable::ReleaseMembers();
+ // mManagerPtr must be null before returning to prevent the background
+ // thread from racing to release it during the destruction of this runnable.
+ mManagerPtr = nsnull;
+ }
+
+private:
+ nsRefPtr<BluetoothManager> mManagerPtr;
+ bool mEnabled;
};
BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow) :
- mEnabled(false),
- mName(nsDependentCString("/"))
+ mEnabled(false)
{
BindToOwner(aWindow);
+ mName.AssignLiteral("/");
}
BluetoothManager::~BluetoothManager()
{
- if(NS_FAILED(UnregisterBluetoothEventHandler(mName, this))) {
- NS_WARNING("Failed to unregister object with observer!");
+ BluetoothService* bs = BluetoothService::Get();
+ // We can be null on shutdown, where this might happen
+ if (bs) {
+ if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mName, this))) {
+ NS_WARNING("Failed to unregister object with observer!");
+ }
}
}
NS_IMETHODIMP
BluetoothManager::SetEnabled(bool aEnabled, nsIDOMDOMRequest** aDomRequest)
{
+ BluetoothService* bs = BluetoothService::Get();
+ MOZ_ASSERT(bs);
+
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
- NS_ERROR("No DOMRequest Service!");
+ NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> request;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!mToggleBtThread) {
- mToggleBtThread = new LazyIdleThread(15000, NS_LITERAL_CSTRING("Bluetooth"));
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Can't create DOM request!");
+ return NS_ERROR_FAILURE;
}
- nsCOMPtr<nsIRunnable> r = new ToggleBtTask(aEnabled, request, this);
-
- rv = mToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsRefPtr<BluetoothReplyRunnable> results = new ToggleBtResultTask(this, request, aEnabled);
+ if (aEnabled) {
+ if (NS_FAILED(bs->Start(results))) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+ else {
+ if (NS_FAILED(bs->Stop(results))) {
+ return NS_ERROR_FAILURE;
+ }
+ }
request.forget(aDomRequest);
-
return NS_OK;
}
NS_IMETHODIMP
BluetoothManager::GetEnabled(bool* aEnabled)
{
*aEnabled = mEnabled;
- return NS_OK;
+ return NS_OK;
}
NS_IMETHODIMP
-BluetoothManager::GetDefaultAdapter(nsIDOMBluetoothAdapter** aAdapter)
+BluetoothManager::GetDefaultAdapter(nsIDOMDOMRequest** aAdapter)
{
- nsCString path;
- nsresult rv = GetDefaultAdapterPathInternal(path);
- if(NS_FAILED(rv)) {
- NS_WARNING("Cannot fetch adapter path!");
+ BluetoothService* bs = BluetoothService::Get();
+ MOZ_ASSERT(bs);
+
+ nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+
+ if (!rs) {
+ NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
- nsRefPtr<BluetoothAdapter> adapter = BluetoothAdapter::Create(path);
- adapter.forget(aAdapter);
+
+ nsCOMPtr<nsIDOMDOMRequest> request;
+ nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Can't create DOMRequest!");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsRefPtr<BluetoothReplyRunnable> results = new GetAdapterTask(this, request);
+
+ if (NS_FAILED(bs->GetDefaultAdapterPathInternal(results))) {
+ return NS_ERROR_FAILURE;
+ }
+ request.forget(aAdapter);
return NS_OK;
}
// static
already_AddRefed<BluetoothManager>
BluetoothManager::Create(nsPIDOMWindow* aWindow) {
+
nsRefPtr<BluetoothManager> manager = new BluetoothManager(aWindow);
- nsDependentCString name("/");
- if(NS_FAILED(RegisterBluetoothEventHandler(name, manager))) {
- NS_WARNING("Failed to register object with observer!");
- return NULL;
+ BluetoothService* bs = BluetoothService::Get();
+ MOZ_ASSERT(bs);
+
+ if (NS_FAILED(bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), manager))) {
+ NS_ERROR("Failed to register object with observer!");
+ return nsnull;
}
+
return manager.forget();
}
nsresult
NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
nsIDOMBluetoothManager** aBluetoothManager)
{
NS_ASSERTION(aWindow, "Null pointer!");
bool allowed;
nsresult rv = nsContentUtils::IsOnPrefWhitelist(aWindow, DOM_BLUETOOTH_URL_PREF, &allowed);
NS_ENSURE_SUCCESS(rv, rv);
-
+
if (!allowed) {
- *aBluetoothManager = NULL;
+ *aBluetoothManager = nsnull;
return NS_OK;
}
nsRefPtr<BluetoothManager> bluetoothManager = BluetoothManager::Create(aWindow);
-
+ if (!bluetoothManager) {
+ NS_ERROR("Cannot create bluetooth manager!");
+ return NS_ERROR_FAILURE;
+ }
bluetoothManager.forget(aBluetoothManager);
return NS_OK;
}
-void BluetoothManager::Notify(const BluetoothEvent& aData) {
- printf("Received an manager message!\n");
+void
+BluetoothManager::Notify(const BluetoothSignal& aData)
+{
+#ifdef DEBUG
+ nsCString warningMsg;
+ warningMsg.AssignLiteral("Not handling manager signal: ");
+ warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
+ NS_WARNING(warningMsg.get());
+#endif
}
--- a/dom/bluetooth/BluetoothManager.h
+++ b/dom/bluetooth/BluetoothManager.h
@@ -5,50 +5,47 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluetoothmanager_h__
#define mozilla_dom_bluetooth_bluetoothmanager_h__
#include "BluetoothCommon.h"
#include "nsDOMEventTargetHelper.h"
#include "nsIDOMBluetoothManager.h"
-#include "nsWeakReference.h"
#include "mozilla/Observer.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothManager : public nsDOMEventTargetHelper
, public nsIDOMBluetoothManager
- , public BluetoothEventObserver
+ , public BluetoothSignalObserver
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMBLUETOOTHMANAGER
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothManager,
nsDOMEventTargetHelper)
inline void SetEnabledInternal(bool aEnabled) {mEnabled = aEnabled;}
static already_AddRefed<BluetoothManager>
Create(nsPIDOMWindow* aWindow);
- void Notify(const BluetoothEvent& aData);
+ void Notify(const BluetoothSignal& aData);
private:
BluetoothManager() {}
BluetoothManager(nsPIDOMWindow* aWindow);
~BluetoothManager();
bool mEnabled;
- nsCString mName;
+ nsString mName;
NS_DECL_EVENT_HANDLER(enabled)
-
- nsCOMPtr<nsIEventTarget> mToggleBtThread;
};
END_BLUETOOTH_NAMESPACE
nsresult NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
nsIDOMBluetoothManager** aBluetoothManager);
#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothNullServiceFactory.cpp
@@ -0,0 +1,16 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothService.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothService*
+BluetoothService::Create()
+{
+ NS_WARNING("Bluetooth not implemented for this platform!");
+ return nsnull;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
+#include "nsIDOMDOMRequest.h"
+#include "jsapi.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+nsresult
+BluetoothReplyRunnable::FireReply(const jsval& aVal)
+{
+ nsCOMPtr<nsIDOMRequestService> rs =
+ do_GetService("@mozilla.org/dom/dom-request-service;1");
+
+ if (!rs) {
+ NS_WARNING("No DOMRequest Service!");
+ return NS_ERROR_FAILURE;
+ }
+
+
+ return mReply->type() == BluetoothReply::TBluetoothReplySuccess ?
+ rs->FireSuccess(mDOMRequest, aVal) :
+ rs->FireError(mDOMRequest, mReply->get_BluetoothReplyError().error());
+}
+
+nsresult
+BluetoothReplyRunnable::FireErrorString()
+{
+ nsCOMPtr<nsIDOMRequestService> rs =
+ do_GetService("@mozilla.org/dom/dom-request-service;1");
+
+ if (!rs) {
+ NS_WARNING("No DOMRequest Service!");
+ return NS_ERROR_FAILURE;
+ }
+
+ return rs->FireError(mDOMRequest, mErrorString);
+}
+
+NS_IMETHODIMP
+BluetoothReplyRunnable::Run()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsresult rv;
+
+ MOZ_ASSERT(mDOMRequest);
+
+ if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
+ rv = FireReply(JSVAL_VOID);
+ } else {
+ jsval v;
+ if (!ParseSuccessfulReply(&v)) {
+ rv = FireErrorString();
+ } else {
+ rv = FireReply(v);
+ }
+ }
+
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Could not fire DOMRequest!");
+ }
+
+ ReleaseMembers();
+ if (mDOMRequest) {
+ NS_WARNING("mDOMRequest still alive! Deriving class should call BluetoothReplyRunnable::ReleaseMembers()!");
+ }
+
+ return rv;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothReplyRunnable.h
@@ -0,0 +1,87 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
+#define mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
+
+#include "BluetoothCommon.h"
+#include "nsThreadUtils.h"
+#include "jsapi.h"
+
+class nsIDOMDOMRequest;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothReply;
+
+class BluetoothReplyRunnable : public nsRunnable
+{
+public:
+ NS_DECL_NSIRUNNABLE
+
+ BluetoothReplyRunnable(nsIDOMDOMRequest* aReq) :
+ mDOMRequest(aReq)
+ {
+ }
+
+ void SetReply(BluetoothReply* aReply)
+ {
+ mReply = aReply;
+ }
+
+ void SetError(const nsAString& aError)
+ {
+ mErrorString = aError;
+ }
+
+ virtual void ReleaseMembers()
+ {
+ mDOMRequest = nsnull;
+ }
+
+protected:
+ virtual ~BluetoothReplyRunnable()
+ {
+ }
+
+ virtual bool ParseSuccessfulReply(jsval* aValue) = 0;
+
+ // This is an autoptr so we don't have to bring the ipdl include into the
+ // header. We assume we'll only be running this once and it should die on
+ // scope out of Run() anyways.
+ nsAutoPtr<BluetoothReply> mReply;
+
+private:
+ nsresult FireReply(const jsval& aVal);
+ nsresult FireErrorString();
+
+ nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
+ nsString mErrorString;
+};
+
+class BluetoothVoidReplyRunnable : public BluetoothReplyRunnable
+{
+public:
+ BluetoothVoidReplyRunnable(nsIDOMDOMRequest* aReq) :
+ BluetoothReplyRunnable(aReq)
+ {
+ }
+
+ virtual void ReleaseMembers()
+ {
+ BluetoothReplyRunnable::ReleaseMembers();
+ }
+protected:
+ virtual bool ParseSuccessfulReply(jsval* aValue)
+ {
+ *aValue = JSVAL_VOID;
+ return true;
+ }
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -0,0 +1,242 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
+
+#include "nsIDOMDOMRequest.h"
+#include "nsThreadUtils.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsObserverService.h"
+#include "mozilla/Services.h"
+#include "mozilla/LazyIdleThread.h"
+#include "mozilla/Util.h"
+
+using namespace mozilla;
+
+USING_BLUETOOTH_NAMESPACE
+
+nsRefPtr<BluetoothService> gBluetoothService;
+nsCOMPtr<nsIThread> gToggleBtThread;
+int gPendingInitCount = 0;
+bool gInShutdown = false;
+
+NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
+
+class ToggleBtAck : public nsRunnable
+{
+public:
+ NS_IMETHOD Run()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ gPendingInitCount--;
+
+ if (gPendingInitCount) {
+ return NS_OK;
+ }
+
+ if (gInShutdown) {
+ gBluetoothService = nsnull;
+ }
+
+ nsCOMPtr<nsIThread> t;
+ gToggleBtThread.swap(t);
+ t->Shutdown();
+ return NS_OK;
+ }
+};
+
+class ToggleBtTask : public nsRunnable
+{
+public:
+ ToggleBtTask(bool aEnabled,
+ BluetoothReplyRunnable* aRunnable)
+ : mEnabled(aEnabled),
+ mRunnable(aRunnable)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ }
+
+ NS_IMETHOD Run()
+ {
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ nsString replyError;
+ if (mEnabled) {
+ if (NS_FAILED(gBluetoothService->StartInternal())) {
+ replyError.AssignLiteral("Bluetooth service not available - We should never reach this point!");
+ }
+ }
+ else {
+ if (NS_FAILED(gBluetoothService->StopInternal())) {
+ replyError.AssignLiteral("Bluetooth service not available - We should never reach this point!");
+ }
+ }
+
+ // Always has to be called since this is where we take care of our reference
+ // count for runnables. If there's an error, replyError won't be empty, so
+ // consider our status flipped.
+ nsCOMPtr<nsIRunnable> ackTask = new ToggleBtAck();
+ if (NS_FAILED(NS_DispatchToMainThread(ackTask))) {
+ NS_WARNING("Failed to dispatch to main thread!");
+ }
+
+ if (!mRunnable) {
+ return NS_OK;
+ }
+
+ // Reply will be deleted by the runnable after running on main thread
+ BluetoothReply* reply;
+ if (!replyError.IsEmpty()) {
+ reply = new BluetoothReply(BluetoothReplyError(replyError));
+ }
+ else {
+ reply = new BluetoothReply(BluetoothReplySuccess());
+ }
+ mRunnable->SetReply(reply);
+
+ if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
+ NS_WARNING("Failed to dispatch to main thread!");
+ }
+
+ return NS_OK;
+ }
+
+private:
+ bool mEnabled;
+ nsRefPtr<BluetoothReplyRunnable> mRunnable;
+};
+
+nsresult
+BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
+ BluetoothSignalObserver* aHandler)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ BluetoothSignalObserverList* ol;
+ if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
+ ol = new BluetoothSignalObserverList();
+ mBluetoothSignalObserverTable.Put(aNodeName, ol);
+ }
+ ol->AddObserver(aHandler);
+ return NS_OK;
+}
+
+nsresult
+BluetoothService::UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
+ BluetoothSignalObserver* aHandler)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ BluetoothSignalObserverList* ol;
+ if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
+ NS_WARNING("Node does not exist to remove BluetoothSignalListener from!");
+ return NS_OK;
+ }
+ ol->RemoveObserver(aHandler);
+ if (ol->Length() == 0) {
+ mBluetoothSignalObserverTable.Remove(aNodeName);
+ }
+ return NS_OK;
+}
+
+nsresult
+BluetoothService::DistributeSignal(const BluetoothSignal& signal)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ // Notify observers that a message has been sent
+ BluetoothSignalObserverList* ol;
+ if (!mBluetoothSignalObserverTable.Get(signal.path(), &ol)) {
+ return NS_OK;
+ }
+ ol->Broadcast(signal);
+ return NS_OK;
+}
+
+nsresult
+BluetoothService::StartStopBluetooth(BluetoothReplyRunnable* aResultRunnable,
+ bool aStart)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // If we're shutting down, bail early.
+ if (gInShutdown && aStart) {
+ NS_ERROR("Start called while in shutdown!");
+ return NS_ERROR_FAILURE;
+ }
+ if (!gToggleBtThread) {
+ nsresult rv = NS_NewNamedThread("BluetoothCtrl",
+ getter_AddRefs(gToggleBtThread));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ nsCOMPtr<nsIRunnable> r = new ToggleBtTask(aStart, aResultRunnable);
+ if (NS_FAILED(gToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL))) {
+ NS_WARNING("Cannot dispatch firmware loading task!");
+ return NS_ERROR_FAILURE;
+ }
+ gPendingInitCount++;
+ return NS_OK;
+}
+
+nsresult
+BluetoothService::Start(BluetoothReplyRunnable* aResultRunnable)
+{
+ return StartStopBluetooth(aResultRunnable, true);
+}
+
+nsresult
+BluetoothService::Stop(BluetoothReplyRunnable* aResultRunnable)
+{
+ return StartStopBluetooth(aResultRunnable, false);
+}
+
+// static
+BluetoothService*
+BluetoothService::Get()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // If we already exist, exit early
+ if (gBluetoothService) {
+ return gBluetoothService;
+ }
+
+ // If we're in shutdown, don't create a new instance
+ if (gInShutdown) {
+ NS_WARNING("BluetoothService returns null during shutdown");
+ return nsnull;
+ }
+
+ // Create new instance, register, return
+ gBluetoothService = BluetoothService::Create();
+ if (!gBluetoothService) {
+ NS_WARNING("Cannot create bluetooth service!");
+ return nsnull;
+ }
+ nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+ MOZ_ASSERT(obs);
+
+ if (NS_FAILED(obs->AddObserver(gBluetoothService, "xpcom-shutdown", false))) {
+ NS_ERROR("AddObserver failed!");
+ }
+ return gBluetoothService;
+}
+
+nsresult
+BluetoothService::Observe(nsISupports* aSubject, const char* aTopic,
+ const PRUnichar* aData)
+{
+ NS_ASSERTION(!strcmp(aTopic, "xpcom-shutdown"),
+ "BluetoothService got unexpected topic!");
+ gInShutdown = true;
+ nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+ if (obs && NS_FAILED(obs->RemoveObserver(this, "xpcom-shutdown"))) {
+ NS_WARNING("Can't unregister bluetooth service with xpcom shutdown!");
+ }
+
+ return Stop(nsnull);
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothService.h
@@ -0,0 +1,171 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetootheventservice_h__
+#define mozilla_dom_bluetooth_bluetootheventservice_h__
+
+#include "nsThreadUtils.h"
+#include "nsClassHashtable.h"
+#include "nsIObserver.h"
+#include "BluetoothCommon.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothSignal;
+class BluetoothReplyRunnable;
+class BluetoothNamedValue;
+
+class BluetoothService : public nsIObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ /**
+ * Add a message handler object from message distribution observer.
+ * Must be called from the main thread.
+ *
+ * @param aNodeName Node name of the object
+ * @param aMsgHandler Weak pointer to the object
+ *
+ * @return NS_OK on successful addition to observer, NS_ERROR_FAILED
+ * otherwise
+ */
+ nsresult RegisterBluetoothSignalHandler(const nsAString& aNodeName,
+ BluetoothSignalObserver* aMsgHandler);
+
+ /**
+ * Remove a message handler object from message distribution observer.
+ * Must be called from the main thread.
+ *
+ * @param aNodeName Node name of the object
+ * @param aMsgHandler Weak pointer to the object
+ *
+ * @return NS_OK on successful removal from observer service,
+ * NS_ERROR_FAILED otherwise
+ */
+ nsresult UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
+ BluetoothSignalObserver* aMsgHandler);
+
+ /**
+ * Distribute a signal to the observer list
+ *
+ * @param aSignal Signal object to distribute
+ *
+ * @return NS_OK if signal distributed, NS_ERROR_FAILURE on error
+ */
+ nsresult DistributeSignal(const BluetoothSignal& aEvent);
+
+ /**
+ * Start bluetooth services. Starts up any threads and connections that
+ * bluetooth needs to operate on the current platform. Assumed to be run on
+ * the main thread with delayed return for blocking startup functions via
+ * runnable.
+ *
+ * @param aResultRunnable Runnable object to execute after bluetooth has
+ * either come up or failed. Runnable should check existence of
+ * BluetoothService via Get() function to see if service started correctly.
+ *
+ * @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
+ * otherwise
+ */
+ nsresult Start(BluetoothReplyRunnable* aResultRunnable);
+
+ /**
+ * Stop bluetooth services. Starts up any threads and connections that
+ * bluetooth needs to operate on the current platform. Assumed to be run on
+ * the main thread with delayed return for blocking startup functions via
+ * runnable.
+ *
+ * @param aResultRunnable Runnable object to execute after bluetooth has
+ * either shut down or failed. Runnable should check lack of existence of
+ * BluetoothService via Get() function to see if service stopped correctly.
+ *
+ * @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
+ * otherwise
+ */
+ nsresult Stop(BluetoothReplyRunnable* aResultRunnable);
+
+ /**
+ * Returns the BluetoothService singleton. Only to be called from main thread.
+ *
+ * @param aService Pointer to return singleton into.
+ *
+ * @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise (if service
+ * has not yet been started, for instance)
+ */
+ static BluetoothService* Get();
+
+ /**
+ * Returns the path of the default adapter, implemented via a platform
+ * specific method.
+ *
+ * @return Default adapter path/name on success, NULL otherwise
+ */
+ virtual nsresult GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable) = 0;
+
+ /**
+ * Stop device discovery (platform specific implementation)
+ *
+ * @param aAdapterPath Adapter to stop discovery on
+ *
+ * @return NS_OK if discovery stopped correctly, false otherwise
+ */
+ virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
+ BluetoothReplyRunnable* aRunnable) = 0;
+
+ /**
+ * Start device discovery (platform specific implementation)
+ *
+ * @param aAdapterPath Adapter to start discovery on
+ *
+ * @return NS_OK if discovery stopped correctly, false otherwise
+ */
+ virtual nsresult StartDiscoveryInternal(const nsAString& aAdapterPath,
+ BluetoothReplyRunnable* aRunnable) = 0;
+
+ /**
+ * Platform specific startup functions go here. Usually deals with member
+ * variables, so not static. Guaranteed to be called outside of main thread.
+ *
+ * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
+ */
+ virtual nsresult StartInternal() = 0;
+
+ /**
+ * Platform specific startup functions go here. Usually deals with member
+ * variables, so not static. Guaranteed to be called outside of main thread.
+ *
+ * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
+ */
+ virtual nsresult StopInternal() = 0;
+
+protected:
+ BluetoothService()
+ {
+ mBluetoothSignalObserverTable.Init();
+ }
+
+ virtual ~BluetoothService()
+ {
+ }
+
+ nsresult StartStopBluetooth(BluetoothReplyRunnable* aResultRunnable,
+ bool aStart);
+ // This function is implemented in platform-specific BluetoothServiceFactory
+ // files
+ static BluetoothService* Create();
+
+ typedef mozilla::ObserverList<BluetoothSignal> BluetoothSignalObserverList;
+ typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
+ BluetoothSignalObserverTable;
+
+ BluetoothSignalObserverTable mBluetoothSignalObserverTable;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
deleted file mode 100644
--- a/dom/bluetooth/BluetoothUtils.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=40: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_bluetoothutils_h__
-#define mozilla_dom_bluetooth_bluetoothutils_h__
-
-#include "BluetoothCommon.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-/**
- * BluetoothUtil functions are used to dispatch messages to Bluetooth DOM
- * objects on the main thread, as well as provide platform indenpendent access
- * to BT functionality. Tasks for polling for outside messages will usually
- * happen on the IO Thread (see ipc/dbus for instance), and these messages will
- * be encased in runnables that will then be distributed via observers managed
- * here.
- */
-
-/**
- * Add a message handler object from message distribution observer.
- * Must be called from the main thread.
- *
- * @param aNodeName Node name of the object
- * @param aMsgHandler Weak pointer to the object
- *
- * @return NS_OK on successful addition to observer, NS_ERROR_FAILED
- * otherwise
- */
-nsresult RegisterBluetoothEventHandler(const nsCString& aNodeName,
- BluetoothEventObserver *aMsgHandler);
-
-/**
- * Remove a message handler object from message distribution observer.
- * Must be called from the main thread.
- *
- * @param aNodeName Node name of the object
- * @param aMsgHandler Weak pointer to the object
- *
- * @return NS_OK on successful removal from observer service,
- * NS_ERROR_FAILED otherwise
- */
-nsresult UnregisterBluetoothEventHandler(const nsCString& aNodeName,
- BluetoothEventObserver *aMsgHandler);
-
-/**
- * Returns the path of the default adapter, implemented via a platform
- * specific method.
- *
- * @return Default adapter path/name on success, NULL otherwise
- */
-nsresult GetDefaultAdapterPathInternal(nsCString& aAdapterPath);
-
-/**
- * Set up variables and start the platform specific connection. Must
- * be called from main thread.
- *
- * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
- * otherwise
- */
-nsresult StartBluetoothConnection();
-
-/**
- * Stop the platform specific connection. Must be called from main
- * thread.
- *
- * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
- * otherwise
- */
-nsresult StopBluetoothConnection();
-
-END_BLUETOOTH_NAMESPACE
-
-#endif
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -10,46 +10,63 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
LIBRARY_NAME = dombluetooth_s
XPIDL_MODULE = dom_bluetooth
LIBXUL_LIBRARY = 1
FORCE_STATIC_LIB = 1
-ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
-VPATH += $(srcdir)/linux
-LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
-endif
-
-ifdef MOZ_ENABLE_DBUS
-VPATH += $(srcdir)/linux
-LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
-endif
-
include $(topsrcdir)/dom/dom-config.mk
-CPPSRCS = \
+CPPSRCS += \
+ BluetoothService.cpp \
BluetoothManager.cpp \
BluetoothAdapter.cpp \
- BluetoothFirmware.cpp \
+ BluetoothDevice.cpp \
+ BluetoothDeviceEvent.cpp \
+ BluetoothReplyRunnable.cpp \
$(NULL)
-ifdef MOZ_ENABLE_DBUS
-CPPSRCS += BluetoothDBusUtils.cpp
-endif
-
-ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
-CPPSRCS += BluetoothDBusUtils.cpp
-endif
-
XPIDLSRCS = \
nsIDOMNavigatorBluetooth.idl \
nsIDOMBluetoothManager.idl \
nsIDOMBluetoothAdapter.idl \
+ nsIDOMBluetoothDevice.idl \
+ nsIDOMBluetoothDeviceEvent.idl \
$(NULL)
+ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+VPATH += \
+ $(srcdir)/linux \
+ $(srcdir)/gonk \
+ $(NULL)
+LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
+CPPSRCS += \
+ BluetoothDBusService.cpp \
+ BluetoothGonkService.cpp \
+ BluetoothGonkServiceFactory.cpp \
+ $(NULL)
+else
+ifdef MOZ_ENABLE_DBUS
+VPATH += $(srcdir)/linux
+LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
+CPPSRCS += \
+ BluetoothDBusService.cpp \
+ BluetoothDBusServiceFactory.cpp \
+ $(NULL)
+CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
+CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
+else
+CPPSRCS += BluetoothNullServiceFactory.cpp
+endif
+endif
+
+LOCAL_INCLUDES += -I$(DEPTH)/ipc/ipdl/_ipdlheaders/mozilla/dom/bluetooth/
+
+# Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
+# subdirectory
+LOCAL_INCLUDES += $(VPATH:%=-I%)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk
-ifdef MOZ_ENABLE_DBUS
-CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
-CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
-endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/gonk/BluetoothGonkService.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothGonkService.h"
+#include "BluetoothDBusService.h"
+
+#include "nsDebug.h"
+#include "nsError.h"
+#include <dlfcn.h>
+
+USING_BLUETOOTH_NAMESPACE
+
+static struct BluedroidFunctions
+{
+ bool initialized;
+ bool tried_initialization;
+
+ BluedroidFunctions() :
+ initialized(false),
+ tried_initialization(false)
+ {
+ }
+
+ int (* bt_enable)();
+ int (* bt_disable)();
+ int (* bt_is_enabled)();
+} sBluedroidFunctions;
+
+bool
+EnsureBluetoothInit()
+{
+ if (sBluedroidFunctions.tried_initialization)
+ {
+ return sBluedroidFunctions.initialized;
+ }
+
+ sBluedroidFunctions.initialized = false;
+ sBluedroidFunctions.tried_initialization = true;
+
+ void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
+
+ if (!handle) {
+ NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
+ return false;
+ }
+
+ sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
+ if (!sBluedroidFunctions.bt_enable) {
+ NS_ERROR("Failed to attach bt_enable function");
+ return false;
+ }
+ sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
+ if (!sBluedroidFunctions.bt_disable) {
+ NS_ERROR("Failed to attach bt_disable function");
+ return false;
+ }
+ sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
+ if (!sBluedroidFunctions.bt_is_enabled) {
+ NS_ERROR("Failed to attach bt_is_enabled function");
+ return false;
+ }
+ sBluedroidFunctions.initialized = true;
+ return true;
+}
+
+int
+IsBluetoothEnabled()
+{
+ return sBluedroidFunctions.bt_is_enabled();
+}
+
+int
+EnableBluetooth()
+{
+ return sBluedroidFunctions.bt_enable();
+}
+
+int
+DisableBluetooth()
+{
+ return sBluedroidFunctions.bt_disable();
+}
+
+nsresult
+StartStopGonkBluetooth(bool aShouldEnable)
+{
+ bool result;
+
+ // Platform specific check for gonk until object is divided in
+ // different implementations per platform. Linux doesn't require
+ // bluetooth firmware loading, but code should work otherwise.
+ if (!EnsureBluetoothInit()) {
+ NS_ERROR("Failed to load bluedroid library.\n");
+ return NS_ERROR_FAILURE;
+ }
+
+ // return 1 if it's enabled, 0 if it's disabled, and -1 on error
+ int isEnabled = IsBluetoothEnabled();
+
+ if ((isEnabled == 1 && aShouldEnable) || (isEnabled == 0 && !aShouldEnable)) {
+ result = true;
+ } else if (isEnabled < 0) {
+ result = false;
+ } else if (aShouldEnable) {
+ result = (EnableBluetooth() == 0) ? true : false;
+ } else {
+ result = (DisableBluetooth() == 0) ? true : false;
+ }
+ if (!result) {
+ NS_WARNING("Could not set gonk bluetooth firmware!");
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+BluetoothGonkService::StartInternal()
+{
+ NS_ASSERTION(!NS_IsMainThread(), "This should not run on the main thread!");
+
+ nsresult ret;
+
+ ret = StartStopGonkBluetooth(true);
+
+ if (NS_FAILED(ret)) {
+ return ret;
+ }
+
+ return BluetoothDBusService::StartInternal();
+}
+
+nsresult
+BluetoothGonkService::StopInternal()
+{
+ NS_ASSERTION(!NS_IsMainThread(), "This should not run on the main thread!");
+ nsresult ret;
+
+ ret = StartStopGonkBluetooth(false);
+
+ if (NS_FAILED(ret)) {
+ return ret;
+ }
+
+ return BluetoothDBusService::StopInternal();
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/gonk/BluetoothGonkService.h
@@ -0,0 +1,48 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothgonkservice_h__
+#define mozilla_dom_bluetooth_bluetoothgonkservice_h__
+
+#include "BluetoothCommon.h"
+#include "BluetoothDBusService.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+/**
+ * BluetoothService functions are used to dispatch messages to Bluetooth DOM
+ * objects on the main thread, as well as provide platform indenpendent access
+ * to BT functionality. Tasks for polling for outside messages will usually
+ * happen on the IO Thread (see ipc/dbus for instance), and these messages will
+ * be encased in runnables that will then be distributed via observers managed
+ * here.
+ */
+
+class BluetoothGonkService : public BluetoothDBusService
+{
+public:
+ /**
+ * Set up variables and start the platform specific connection. Must
+ * be called from main thread.
+ *
+ * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+ * otherwise
+ */
+ virtual nsresult StartInternal();
+
+ /**
+ * Stop the platform specific connection. Must be called from main
+ * thread.
+ *
+ * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+ * otherwise
+ */
+ virtual nsresult StopInternal();
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/gonk/BluetoothGonkServiceFactory.cpp
@@ -0,0 +1,15 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothGonkService.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothService*
+BluetoothService::Create()
+{
+ return new BluetoothGonkService();
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothTypes.ipdlh
@@ -0,0 +1,62 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+/**
+ * Value structure for returns from bluetooth. Currently modeled after dbus
+ * returns, which can be a 32-bit int, an UTF16 string, a bool, or an array of
+ * UTF16 strings. Can also hold key-value pairs for dictionary-ish access.
+ *
+ */
+union BluetoothValue
+{
+ uint32_t;
+ nsString;
+ bool;
+ nsString[];
+ BluetoothNamedValue[];
+};
+
+/**
+ * Key-value pair for dicts returned by the bluetooth backend. Used for things
+ * like property updates, where the property will have a name and a type.
+ *
+ */
+struct BluetoothNamedValue
+{
+ nsString name;
+ BluetoothValue value;
+};
+
+struct BluetoothSignal
+{
+ nsString name;
+ nsString path;
+ BluetoothValue value;
+};
+
+struct BluetoothReplySuccess
+{
+ BluetoothValue value;
+};
+
+struct BluetoothReplyError
+{
+ nsString error;
+};
+
+union BluetoothReply
+{
+ BluetoothReplySuccess;
+ BluetoothReplyError;
+};
+
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/ipdl.mk
@@ -0,0 +1,7 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+IPDLSRCS = \
+ BluetoothTypes.ipdlh \
+ $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -0,0 +1,577 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "base/basictypes.h"
+#include "BluetoothDBusService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
+
+#include <cstdio>
+#include <dbus/dbus.h>
+
+#include "nsIDOMDOMRequest.h"
+#include "nsAutoPtr.h"
+#include "nsThreadUtils.h"
+#include "nsDebug.h"
+#include "nsClassHashtable.h"
+#include "mozilla/ipc/DBusThread.h"
+#include "mozilla/ipc/DBusUtils.h"
+#include "mozilla/ipc/RawDBusConnection.h"
+#include "mozilla/Util.h"
+
+/**
+ * Some rules for dealing with memory in DBus:
+ * - A DBusError only needs to be deleted if it's been set, not just
+ * initialized. This is why LOG_AND_FREE... is called only when an error is
+ * set, and the macro cleans up the error itself.
+ * - A DBusMessage needs to be unrefed when it is newed explicitly. DBusMessages
+ * from signals do not need to be unrefed, as they will be cleaned by DBus
+ * after DBUS_HANDLER_RESULT_HANDLED is returned from the filter.
+ */
+
+using namespace mozilla;
+using namespace mozilla::ipc;
+USING_BLUETOOTH_NAMESPACE
+
+#undef LOG
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
+#else
+#define BTDEBUG true
+#define LOG(args...) if (BTDEBUG) printf(args);
+#endif
+
+#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
+#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
+#define BLUEZ_DBUS_BASE_PATH "/org/bluez"
+#define BLUEZ_DBUS_BASE_IFC "org.bluez"
+#define BLUEZ_ERROR_IFC "org.bluez.Error"
+
+typedef struct {
+ const char* name;
+ int type;
+} Properties;
+
+static Properties remote_device_properties[] = {
+ {"Address", DBUS_TYPE_STRING},
+ {"Name", DBUS_TYPE_STRING},
+ {"Icon", DBUS_TYPE_STRING},
+ {"Class", DBUS_TYPE_UINT32},
+ {"UUIDs", DBUS_TYPE_ARRAY},
+ {"Services", DBUS_TYPE_ARRAY},
+ {"Paired", DBUS_TYPE_BOOLEAN},
+ {"Connected", DBUS_TYPE_BOOLEAN},
+ {"Trusted", DBUS_TYPE_BOOLEAN},
+ {"Blocked", DBUS_TYPE_BOOLEAN},
+ {"Alias", DBUS_TYPE_STRING},
+ {"Nodes", DBUS_TYPE_ARRAY},
+ {"Adapter", DBUS_TYPE_OBJECT_PATH},
+ {"LegacyPairing", DBUS_TYPE_BOOLEAN},
+ {"RSSI", DBUS_TYPE_INT16},
+ {"TX", DBUS_TYPE_UINT32},
+ {"Broadcaster", DBUS_TYPE_BOOLEAN}
+};
+
+static Properties adapter_properties[] = {
+ {"Address", DBUS_TYPE_STRING},
+ {"Name", DBUS_TYPE_STRING},
+ {"Class", DBUS_TYPE_UINT32},
+ {"Powered", DBUS_TYPE_BOOLEAN},
+ {"Discoverable", DBUS_TYPE_BOOLEAN},
+ {"DiscoverableTimeout", DBUS_TYPE_UINT32},
+ {"Pairable", DBUS_TYPE_BOOLEAN},
+ {"PairableTimeout", DBUS_TYPE_UINT32},
+ {"Discovering", DBUS_TYPE_BOOLEAN},
+ {"Devices", DBUS_TYPE_ARRAY},
+ {"UUIDs", DBUS_TYPE_ARRAY},
+};
+
+static const char* BLUETOOTH_DBUS_SIGNALS[] =
+{
+ "type='signal',interface='org.freedesktop.DBus'",
+ "type='signal',interface='org.bluez.Adapter'",
+ "type='signal',interface='org.bluez.Manager'",
+ "type='signal',interface='org.bluez.Device'",
+ "type='signal',interface='org.bluez.Input'",
+ "type='signal',interface='org.bluez.Network'",
+ "type='signal',interface='org.bluez.NetworkServer'",
+ "type='signal',interface='org.bluez.HealthDevice'",
+ "type='signal',interface='org.bluez.AudioSink'"
+};
+
+class DistributeBluetoothSignalTask : public nsRunnable {
+ BluetoothSignal mSignal;
+public:
+ DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
+ mSignal(aSignal)
+ {
+ }
+
+ NS_IMETHOD
+ Run()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ BluetoothService* bs = BluetoothService::Get();
+ MOZ_ASSERT(bs);
+ return bs->DistributeSignal(mSignal);
+ }
+};
+
+
+bool
+IsDBusMessageError(DBusMessage* aMsg, nsAString& aError)
+{
+ DBusError err;
+ dbus_error_init(&err);
+ if (dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_ERROR) {
+ const char* error_msg;
+ if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_STRING,
+ &error_msg, DBUS_TYPE_INVALID) ||
+ !error_msg) {
+ if (dbus_error_is_set(&err)) {
+ aError = NS_ConvertUTF8toUTF16(err.message);
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return true;
+ }
+ } else {
+ aError = NS_ConvertUTF8toUTF16(error_msg);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
+ const BluetoothValue& aValue, const nsAString& aError)
+{
+ // Reply will be deleted by the runnable after running on main thread
+ BluetoothReply* reply;
+ if (!aError.IsEmpty()) {
+ nsString err(aError);
+ reply = new BluetoothReply(BluetoothReplyError(err));
+ }
+ else {
+ reply = new BluetoothReply(BluetoothReplySuccess(aValue));
+ }
+
+ aRunnable->SetReply(reply);
+ if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
+ NS_WARNING("Failed to dispatch to main thread!");
+ }
+}
+
+void
+GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+ DBusError err;
+ dbus_error_init(&err);
+ nsRefPtr<BluetoothReplyRunnable> replyRunnable =
+ dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
+
+ NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
+
+ nsString replyError;
+ nsString replyPath;
+
+ nsTArray<BluetoothNamedValue> replyValues;
+ BluetoothValue v;
+ if (!IsDBusMessageError(aMsg, replyError)) {
+ NS_ASSERTION(dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN,
+ "Got dbus callback that's not a METHOD_RETURN!");
+ const char* object_path;
+ if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_OBJECT_PATH,
+ &object_path, DBUS_TYPE_INVALID) ||
+ !object_path) {
+ if (dbus_error_is_set(&err)) {
+ replyError = NS_ConvertUTF8toUTF16(err.message);
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ } else {
+ v = NS_ConvertUTF8toUTF16(object_path);
+ }
+ }
+ DispatchBluetoothReply(replyRunnable, v, replyError);
+}
+
+void
+GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+ DBusError err;
+ dbus_error_init(&err);
+ nsRefPtr<BluetoothReplyRunnable> replyRunnable =
+ dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
+
+ NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
+
+ nsString replyError;
+ BluetoothValue v;
+ if (!IsDBusMessageError(aMsg, replyError) &&
+ dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
+ !dbus_message_get_args(aMsg, &err, DBUS_TYPE_INVALID)) {
+ if (dbus_error_is_set(&err)) {
+ replyError = NS_ConvertUTF8toUTF16(err.message);
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ }
+ DispatchBluetoothReply(replyRunnable, v, replyError);
+}
+
+bool
+GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
+ int aPropertiesTypeLen, int* aPropIndex,
+ InfallibleTArray<BluetoothNamedValue>& aProperties)
+{
+ DBusMessageIter prop_val, array_val_iter;
+ char* property = NULL;
+ uint32_t array_type;
+ int i, type;
+
+ if (dbus_message_iter_get_arg_type(&aIter) != DBUS_TYPE_STRING) {
+ return false;
+ }
+
+ dbus_message_iter_get_basic(&aIter, &property);
+
+ if (!dbus_message_iter_next(&aIter) ||
+ dbus_message_iter_get_arg_type(&aIter) != DBUS_TYPE_VARIANT) {
+ return false;
+ }
+
+ for (i = 0; i < aPropertiesTypeLen; i++) {
+ if (!strncmp(property, aPropertyTypes[i].name, strlen(property))) {
+ break;
+ }
+ }
+
+ if (i == aPropertiesTypeLen) {
+ return false;
+ }
+
+ nsString propertyName;
+ propertyName.AssignASCII(aPropertyTypes[i].name);
+ *aPropIndex = i;
+
+ dbus_message_iter_recurse(&aIter, &prop_val);
+ type = aPropertyTypes[*aPropIndex].type;
+
+ NS_ASSERTION(dbus_message_iter_get_arg_type(&prop_val) == type,
+ "Iterator not type we expect!");
+
+ BluetoothValue propertyValue;
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ const char* c;
+ dbus_message_iter_get_basic(&prop_val, &c);
+ propertyValue = NS_ConvertUTF8toUTF16(c);
+ break;
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT16:
+ uint32_t i;
+ dbus_message_iter_get_basic(&prop_val, &i);
+ propertyValue = i;
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ bool b;
+ dbus_message_iter_get_basic(&prop_val, &b);
+ propertyValue = b;
+ break;
+ case DBUS_TYPE_ARRAY:
+ dbus_message_iter_recurse(&prop_val, &array_val_iter);
+ array_type = dbus_message_iter_get_arg_type(&array_val_iter);
+ if (array_type == DBUS_TYPE_OBJECT_PATH ||
+ array_type == DBUS_TYPE_STRING){
+ InfallibleTArray<nsString> arr;
+ do {
+ const char* tmp;
+ dbus_message_iter_get_basic(&array_val_iter, &tmp);
+ nsString s;
+ s = NS_ConvertUTF8toUTF16(tmp);
+ arr.AppendElement(s);
+ } while (dbus_message_iter_next(&array_val_iter));
+ propertyValue = arr;
+ } else {
+ NS_WARNING("Received array type that's not a string array!");
+ }
+ break;
+ default:
+ NS_NOTREACHED("Cannot find dbus message type!");
+ }
+ aProperties.AppendElement(BluetoothNamedValue(propertyName, propertyValue));
+ return true;
+}
+
+void
+ParseProperties(DBusMessageIter* aIter,
+ Properties* aPropertyTypes,
+ const int aPropertiesTypeLen,
+ InfallibleTArray<BluetoothNamedValue>& aProperties)
+{
+ DBusMessageIter dict_entry, dict;
+ int prop_index = -1;
+
+ NS_ASSERTION(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_ARRAY,
+ "Trying to parse a property from something that's not an array!");
+
+ dbus_message_iter_recurse(aIter, &dict);
+
+ do {
+ NS_ASSERTION(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY,
+ "Trying to parse a property from something that's not an dict!");
+ dbus_message_iter_recurse(&dict, &dict_entry);
+
+ if (!GetProperty(dict_entry, aPropertyTypes, aPropertiesTypeLen, &prop_index,
+ aProperties)) {
+ NS_WARNING("Can't create property!");
+ return;
+ }
+ } while (dbus_message_iter_next(&dict));
+}
+
+void
+ParsePropertyChange(DBusMessage* aMsg, Properties* aPropertyTypes,
+ const int aPropertiesTypeLen,
+ InfallibleTArray<BluetoothNamedValue>& aProperties)
+{
+ DBusMessageIter iter;
+ DBusError err;
+ int prop_index = -1;
+
+ dbus_error_init(&err);
+ if (!dbus_message_iter_init(aMsg, &iter)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+ return;
+ }
+
+ if (!GetProperty(iter, aPropertyTypes, aPropertiesTypeLen,
+ &prop_index, aProperties)) {
+ NS_WARNING("Can't get property!");
+ }
+}
+
+// Called by dbus during WaitForAndDispatchEventNative()
+// This function is called on the IOThread
+static
+DBusHandlerResult
+EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
+{
+ NS_ASSERTION(!NS_IsMainThread(), "Shouldn't be called from Main Thread!");
+
+ if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+ LOG("%s: not interested (not a signal).\n", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (dbus_message_get_path(aMsg) == NULL) {
+ LOG("DBusMessage %s has no bluetooth destination, ignoring\n",
+ dbus_message_get_member(aMsg));
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ DBusError err;
+ nsString signalPath;
+ nsString signalName;
+ dbus_error_init(&err);
+ signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(aMsg));
+ LOG("%s: Received signal %s:%s from %s\n", __FUNCTION__,
+ dbus_message_get_interface(aMsg), dbus_message_get_member(aMsg),
+ dbus_message_get_path(aMsg));
+
+ signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
+ BluetoothValue v;
+
+ if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceFound")) {
+
+ DBusMessageIter iter;
+
+ NS_ASSERTION(dbus_message_iter_init(aMsg, &iter),
+ "Can't create message iterator!");
+
+ InfallibleTArray<BluetoothNamedValue> value;
+ const char* addr;
+ dbus_message_iter_get_basic(&iter, &addr);
+ value.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
+ NS_ConvertUTF8toUTF16(addr)));
+
+ if (dbus_message_iter_next(&iter)) {
+ ParseProperties(&iter,
+ remote_device_properties,
+ ArrayLength(remote_device_properties),
+ value);
+ NS_ASSERTION(value.Length() != 0, "Properties returned empty!");
+ v = value;
+ } else {
+ NS_WARNING("DBus iterator not as long as expected!");
+ }
+ } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceDisappeared")) {
+ const char* str;
+ if (!dbus_message_get_args(aMsg, &err,
+ DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+ }
+ v = NS_ConvertUTF8toUTF16(str);
+ } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceCreated")) {
+ const char* str;
+ if (!dbus_message_get_args(aMsg, &err,
+ DBUS_TYPE_OBJECT_PATH, &str,
+ DBUS_TYPE_INVALID)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+ }
+ v = NS_ConvertUTF8toUTF16(str);
+ } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "PropertyChanged")) {
+ InfallibleTArray<BluetoothNamedValue> value;
+ ParsePropertyChange(aMsg,
+ (Properties*)&adapter_properties,
+ ArrayLength(adapter_properties),
+ value);
+ NS_ASSERTION(value.Length() != 0, "Properties returned empty!");
+ v = value;
+ }
+
+ BluetoothSignal signal(signalName, signalPath, v);
+
+ nsRefPtr<DistributeBluetoothSignalTask>
+ t = new DistributeBluetoothSignalTask(signal);
+ if (NS_FAILED(NS_DispatchToMainThread(t))) {
+ NS_WARNING("Failed to dispatch to main thread!");
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+nsresult
+BluetoothDBusService::StartInternal()
+{
+ // This could block. It should never be run on the main thread.
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ if (!StartDBus()) {
+ NS_WARNING("Cannot start DBus thread!");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (mConnection) {
+ return NS_OK;
+ }
+
+ if (NS_FAILED(EstablishDBusConnection())) {
+ NS_WARNING("Cannot start DBus connection!");
+ StopDBus();
+ return NS_ERROR_FAILURE;
+ }
+
+ // Add a filter for all incoming messages_base
+ if (!dbus_connection_add_filter(mConnection, EventFilter,
+ NULL, NULL)) {
+ NS_WARNING("Cannot create DBus Event Filter for DBus Thread!");
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::StopInternal()
+{
+ // This could block. It should never be run on the main thread.
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ if (!mConnection) {
+ StopDBus();
+ return NS_OK;
+ }
+ dbus_connection_remove_filter(mConnection, EventFilter, NULL);
+ mConnection = nsnull;
+ mBluetoothSignalObserverTable.Clear();
+ StopDBus();
+ return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable)
+{
+ if (!mConnection) {
+ NS_ERROR("Bluetooth service not started yet!");
+ return NS_ERROR_FAILURE;
+ }
+ NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+ nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+ if (!dbus_func_args_async(mConnection,
+ 1000,
+ GetObjectPathCallback,
+ (void*)aRunnable,
+ "/",
+ "org.bluez.Manager",
+ "DefaultAdapter",
+ DBUS_TYPE_INVALID)) {
+ NS_WARNING("Could not start async function!");
+ return NS_ERROR_FAILURE;
+ }
+ runnable.forget();
+ return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::SendDiscoveryMessage(const nsAString& aAdapterPath,
+ const char* aMessageName,
+ BluetoothReplyRunnable* aRunnable)
+{
+ if (!mConnection) {
+ NS_WARNING("Bluetooth service not started yet!");
+ return NS_ERROR_FAILURE;
+ }
+ NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+ nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+ const char* s = NS_ConvertUTF16toUTF8(aAdapterPath).get();
+ if (!dbus_func_args_async(mConnection,
+ 1000,
+ GetVoidCallback,
+ (void*)aRunnable,
+ s,
+ DBUS_ADAPTER_IFACE,
+ aMessageName,
+ DBUS_TYPE_INVALID)) {
+ NS_WARNING("Could not start async function!");
+ return NS_ERROR_FAILURE;
+ }
+ runnable.forget();
+ return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::StopDiscoveryInternal(const nsAString& aAdapterPath,
+ BluetoothReplyRunnable* aRunnable)
+{
+ return SendDiscoveryMessage(aAdapterPath, "StopDiscovery", aRunnable);
+}
+
+nsresult
+BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
+ BluetoothReplyRunnable* aRunnable)
+{
+ return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -0,0 +1,84 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothdbuseventservice_h__
+#define mozilla_dom_bluetooth_bluetoothdbuseventservice_h__
+
+#include "BluetoothCommon.h"
+#include "mozilla/ipc/RawDBusConnection.h"
+#include "BluetoothService.h"
+
+class DBusMessage;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+/**
+ * BluetoothService functions are used to dispatch messages to Bluetooth DOM
+ * objects on the main thread, as well as provide platform independent access
+ * to BT functionality. Tasks for polling for outside messages will usually
+ * happen on the IO Thread (see ipc/dbus for instance), and these messages will
+ * be encased in runnables that will then be distributed via observers managed
+ * here.
+ */
+
+class BluetoothDBusService : public BluetoothService
+ , private mozilla::ipc::RawDBusConnection
+{
+public:
+ /**
+ * Set up variables and start the platform specific connection. Must
+ * be called from outside main thread.
+ *
+ * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+ * otherwise
+ */
+ virtual nsresult StartInternal();
+
+ /**
+ * Stop the platform specific connection. Must be called from outside main
+ * thread.
+ *
+ * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+ * otherwise
+ */
+ virtual nsresult StopInternal();
+
+ /**
+ * Returns the path of the default adapter, implemented via a platform
+ * specific method.
+ *
+ * @return Default adapter path/name on success, NULL otherwise
+ */
+ virtual nsresult GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable);
+
+ /**
+ * Start device discovery (platform specific implementation)
+ *
+ * @param aAdapterPath Adapter to start discovery on
+ *
+ * @return NS_OK if discovery stopped correctly, NS_ERROR_FAILURE otherwise
+ */
+ virtual nsresult StartDiscoveryInternal(const nsAString& aAdapterPath,
+ BluetoothReplyRunnable* aRunnable);
+ /**
+ * Stop device discovery (platform specific implementation)
+ *
+ * @param aAdapterPath Adapter to stop discovery on
+ *
+ * @return NS_OK if discovery stopped correctly, NS_ERROR_FAILURE otherwise
+ */
+ virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
+ BluetoothReplyRunnable* aRunnable);
+
+private:
+ nsresult SendDiscoveryMessage(const nsAString& aAdapterPath,
+ const char* aMessageName,
+ BluetoothReplyRunnable* aRunnable);
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/linux/BluetoothDBusServiceFactory.cpp
@@ -0,0 +1,15 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothDBusService.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothService*
+BluetoothService::Create()
+{
+ return new BluetoothDBusService();
+}
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl
@@ -1,12 +1,36 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMEventTarget.idl"
-[scriptable, builtinclass, uuid(fe6602d2-f32f-4b95-bf66-028452bbe6d2)]
+interface nsIDOMDOMRequest;
+interface nsIDOMBluetoothDevice;
+
+[scriptable, builtinclass, uuid(48df7f05-2bbc-4ac8-aa88-9fecd4c24028)]
interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
{
+ readonly attribute DOMString address;
+ [binaryname(AdapterClass)] readonly attribute unsigned long class;
+ readonly attribute bool enabled;
+ readonly attribute bool discovering;
+
+ [implicit_jscontext]
+ readonly attribute jsval devices;
+
+ readonly attribute DOMString name;
+ readonly attribute bool discoverable;
+ // Unit: sec
+ readonly attribute unsigned long discoverableTimeout;
+
+ nsIDOMDOMRequest startDiscovery();
+ nsIDOMDOMRequest stopDiscovery();
+ // Fired when discoverying and any device is discovered.
+ attribute nsIDOMEventListener ondevicefound;
+ // Fired when any device is out of discoverable range.
+ attribute nsIDOMEventListener ondevicedisappeared;
+ // Fired when a property of the adapter is changed
+ attribute nsIDOMEventListener onpropertychanged;
};
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMBluetoothDevice.idl
@@ -0,0 +1,19 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEventTarget.idl"
+
+[scriptable, builtinclass, uuid(2c446123-b5dd-4631-80f6-eda91befd8c9)]
+interface nsIDOMBluetoothDevice : nsIDOMEventTarget
+{
+ readonly attribute DOMString address;
+ readonly attribute DOMString name;
+
+ [binaryname(DeviceClass)] readonly attribute unsigned long class;
+ readonly attribute bool connected;
+ readonly attribute bool paired;
+ attribute nsIDOMEventListener onpropertychanged;
+};
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMBluetoothDeviceEvent.idl
@@ -0,0 +1,15 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEvent.idl"
+
+interface nsIDOMBluetoothDevice;
+
+[scriptable, builtinclass, uuid(49294da3-b698-4a7f-aca2-3f9bc44c7625)]
+interface nsIDOMBluetoothDeviceEvent : nsIDOMEvent
+{
+ readonly attribute nsIDOMBluetoothDevice device;
+};
--- a/dom/bluetooth/nsIDOMBluetoothManager.idl
+++ b/dom/bluetooth/nsIDOMBluetoothManager.idl
@@ -4,16 +4,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMEventTarget.idl"
interface nsIDOMDOMRequest;
interface nsIDOMBluetoothAdapter;
-[scriptable, builtinclass, uuid(9d4bcbad-8904-4985-b366-036d32959312)]
+[scriptable, builtinclass, uuid(1442c310-8233-4670-8aa9-752ad673bae0)]
interface nsIDOMBluetoothManager : nsIDOMEventTarget
{
readonly attribute bool enabled;
- readonly attribute nsIDOMBluetoothAdapter defaultAdapter;
+ nsIDOMDOMRequest getDefaultAdapter();
nsIDOMDOMRequest setEnabled(in boolean enabled);
};
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -14,46 +14,29 @@
#include "nsIXPConnect.h"
#include "jsfriendapi.h"
#include "mozilla/dom/workers/Workers.h"
#ifdef MOZ_WIDGET_GONK
#include "AutoMounter.h"
#endif
#include "mozilla/ipc/Ril.h"
-#ifdef MOZ_B2G_BT
-#include "mozilla/ipc/DBusThread.h"
-#include "BluetoothFirmware.h"
-#include "BluetoothUtils.h"
-#endif
#include "nsContentUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsRadioInterfaceLayer.h"
#include "WifiWorker.h"
-#undef LOG
-#if defined(MOZ_WIDGET_GONK)
-#include <android/log.h>
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkBluetooth", args);
-#else
-#define BTDEBUG true
-#define LOG(args...) if(BTDEBUG) printf(args);
-#endif
+USING_WORKERS_NAMESPACE
-
-USING_WORKERS_NAMESPACE
using namespace mozilla::dom::gonk;
using namespace mozilla::ipc;
#ifdef MOZ_WIDGET_GONK
using namespace mozilla::system;
#endif
-#ifdef MOZ_B2G_BT
-using namespace mozilla::dom::bluetooth;
-#endif
namespace {
NS_DEFINE_CID(kRadioInterfaceLayerCID, NS_RADIOINTERFACELAYER_CID);
NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
// Doesn't carry a reference, we're owned by services.
SystemWorkerManager *gInstance = nsnull;
@@ -224,25 +207,16 @@ SystemWorkerManager::Init()
}
rv = InitWifi(cx);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize WiFi Networking!");
return rv;
}
-#ifdef MOZ_B2G_BT
- rv = InitBluetooth(cx);
- if (NS_FAILED(rv)) {
- NS_WARNING("Failed to initialize Bluetooth!");
- return rv;
- }
-
-#endif
-
#ifdef MOZ_WIDGET_GONK
InitAutoMounter();
#endif
nsCOMPtr<nsIObserverService> obs =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (!obs) {
NS_WARNING("Failed to get observer service!");
@@ -265,19 +239,17 @@ SystemWorkerManager::Shutdown()
mShutdown = true;
#ifdef MOZ_WIDGET_GONK
ShutdownAutoMounter();
#endif
StopRil();
-#ifdef MOZ_B2G_BT
- StopDBus();
-#endif
+
mRILWorker = nsnull;
nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
if (wifi) {
wifi->Shutdown();
wifi = nsnull;
}
mWifiWorker = nsnull;
@@ -380,39 +352,16 @@ SystemWorkerManager::InitWifi(JSContext
{
nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
mWifiWorker = worker;
return NS_OK;
}
-nsresult
-SystemWorkerManager::InitBluetooth(JSContext *cx)
-{
-#ifdef MOZ_B2G_BT
-#ifdef MOZ_WIDGET_GONK
- // We need a platform specific check here to make sure of when we're
- // running on an emulator. Therefore, if we're compiled with gonk,
- // see if we can load functions out of bluedroid. If not, assume
- // it's an emulator and don't start the bluetooth thread.
- if(EnsureBluetoothInit()) {
-#endif
- StartDBus();
- StartBluetoothConnection();
-#ifdef MOZ_WIDGET_GONK
- }
- else {
- LOG("Bluedroid functions not available, assuming running on simulator. Not starting DBus thread.");
- }
-#endif
-#endif
- return NS_OK;
-}
-
NS_IMPL_ISUPPORTS2(SystemWorkerManager, nsIObserver, nsIInterfaceRequestor)
NS_IMETHODIMP
SystemWorkerManager::Observe(nsISupports *aSubject, const char *aTopic,
const PRUnichar *aData)
{
if (!strcmp(aTopic, WORKERS_SHUTDOWN_TOPIC)) {
Shutdown();
--- a/dom/system/gonk/SystemWorkerManager.h
+++ b/dom/system/gonk/SystemWorkerManager.h
@@ -40,18 +40,17 @@ public:
GetInterfaceRequestor();
private:
SystemWorkerManager();
~SystemWorkerManager();
nsresult InitRIL(JSContext *cx);
nsresult InitWifi(JSContext *cx);
- nsresult InitBluetooth(JSContext *cx);
-
+
nsCOMPtr<nsIWorkerHolder> mRILWorker;
nsCOMPtr<nsIWorkerHolder> mWifiWorker;
bool mShutdown;
};
}
}
--- a/ipc/dbus/DBusThread.cpp
+++ b/ipc/dbus/DBusThread.cpp
@@ -41,33 +41,32 @@
#include <poll.h>
#include <list>
#include "base/eintr_wrapper.h"
#include "base/message_loop.h"
#include "nsTArray.h"
#include "nsDataHashtable.h"
-#include "mozilla/RefPtr.h"
#include "mozilla/Monitor.h"
#include "mozilla/Util.h"
#include "mozilla/FileUtils.h"
#include "nsThreadUtils.h"
#include "nsIThread.h"
#include "nsXULAppAPI.h"
#include "nsServiceManagerUtils.h"
#include "nsCOMPtr.h"
#undef LOG
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
#else
#define BTDEBUG true
-#define LOG(args...) if(BTDEBUG) printf(args);
+#define LOG(args...) if (BTDEBUG) printf(args);
#endif
#define DEFAULT_INITIAL_POLLFD_COUNT 8
// Functions for converting between unix events in the poll struct,
// and their dbus definitions
// TODO Add Wakeup to this list once we've moved to ics
@@ -126,24 +125,22 @@ struct PollFdComparator {
// DBus Thread Class prototype
struct DBusThread : public RawDBusConnection
{
DBusThread();
~DBusThread();
bool StartEventLoop();
- void StopEventLoop();
+ bool StopEventLoop();
bool IsEventLoopRunning();
- static void* EventLoop(void* aPtr);
+ void EventLoop();
// Thread members
- pthread_t mThread;
- Mutex mMutex;
- bool mIsRunning;
+ nsCOMPtr<nsIThread> mThread;
// Information about the sockets we're polling. Socket counts
// increase/decrease depending on how many add/remove watch signals
// we're received via the control sockets.
nsTArray<pollfd> mPollData;
nsTArray<DBusWatch*> mWatchData;
// Sockets for receiving dbus control information (watch
@@ -168,62 +165,62 @@ AddWatch(DBusWatch *aWatch, void *aData)
DBusThread *dbt = (DBusThread *)aData;
if (dbus_watch_get_enabled(aWatch)) {
// note that we can't just send the watch and inspect it later
// because we may get a removeWatch call before this data is reacted
// to by our eventloop and remove this watch.. reading the add first
// and then inspecting the recently deceased watch would be bad.
char control = DBUS_EVENT_LOOP_ADD;
- if(write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
+ if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
LOG("Cannot write DBus add watch control data to socket!\n");
return false;
}
// TODO change this to dbus_watch_get_unix_fd once we move to ics
int fd = dbus_watch_get_fd(aWatch);
- if(write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
+ if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
LOG("Cannot write DBus add watch descriptor data to socket!\n");
return false;
}
unsigned int flags = dbus_watch_get_flags(aWatch);
- if(write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
+ if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
LOG("Cannot write DBus add watch flag data to socket!\n");
return false;
}
- if(write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
+ if (write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
LOG("Cannot write DBus add watch struct data to socket!\n");
return false;
}
}
return true;
}
static void
RemoveWatch(DBusWatch *aWatch, void *aData)
{
DBusThread *dbt = (DBusThread *)aData;
char control = DBUS_EVENT_LOOP_REMOVE;
- if(write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
+ if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
LOG("Cannot write DBus remove watch control data to socket!\n");
return;
}
// TODO change this to dbus_watch_get_unix_fd once we move to ics
int fd = dbus_watch_get_fd(aWatch);
- if(write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
+ if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
LOG("Cannot write DBus remove watch descriptor data to socket!\n");
return;
}
unsigned int flags = dbus_watch_get_flags(aWatch);
- if(write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
+ if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
LOG("Cannot write DBus remove watch flag data to socket!\n");
return;
}
}
static void
ToggleWatch(DBusWatch *aWatch, void *aData)
{
@@ -235,107 +232,107 @@ ToggleWatch(DBusWatch *aWatch, void *aDa
}
static void
HandleWatchAdd(DBusThread* aDbt)
{
DBusWatch *watch;
int newFD;
unsigned int flags;
- if(read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
+ if (read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
LOG("Cannot read DBus watch add descriptor data from socket!\n");
return;
}
- if(read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+ if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
LOG("Cannot read DBus watch add flag data from socket!\n");
return;
}
- if(read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
+ if (read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
LOG("Cannot read DBus watch add watch data from socket!\n");
return;
}
short events = DBusFlagsToUnixEvents(flags);
pollfd p;
p.fd = newFD;
p.revents = 0;
p.events = events;
- if(aDbt->mPollData.Contains(p, PollFdComparator())) return;
+ if (aDbt->mPollData.Contains(p, PollFdComparator())) return;
aDbt->mPollData.AppendElement(p);
aDbt->mWatchData.AppendElement(watch);
}
-static void HandleWatchRemove(DBusThread* aDbt) {
+static void HandleWatchRemove(DBusThread* aDbt)
+{
int removeFD;
unsigned int flags;
- if(read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
+ if (read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
LOG("Cannot read DBus watch remove descriptor data from socket!\n");
return;
}
- if(read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+ if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
LOG("Cannot read DBus watch remove flag data from socket!\n");
return;
}
short events = DBusFlagsToUnixEvents(flags);
pollfd p;
p.fd = removeFD;
p.events = events;
int index = aDbt->mPollData.IndexOf(p, 0, PollFdComparator());
// There are times where removes can be requested for watches that
// haven't been added (for example, whenever gecko comes up after
// adapters have already been enabled), so check to make sure we're
// using the watch in the first place
- if(index < 0) {
+ if (index < 0) {
LOG("DBus requested watch removal of non-existant socket, ignoring...");
return;
}
aDbt->mPollData.RemoveElementAt(index);
// DBusWatch pointers are maintained by DBus, so we won't leak by
// removing.
aDbt->mWatchData.RemoveElementAt(index);
}
// DBus Thread Implementation
-DBusThread::DBusThread() : mMutex("DBusGonk.mMutex")
- , mIsRunning(false)
+DBusThread::DBusThread()
{
}
DBusThread::~DBusThread()
{
}
bool
DBusThread::SetUpEventLoop()
{
// If we already have a connection, exit
- if(mConnection) {
+ if (mConnection) {
return false;
}
dbus_threads_init_default();
DBusError err;
dbus_error_init(&err);
// If we can't establish a connection to dbus, nothing else will work
nsresult rv = EstablishDBusConnection();
- if(NS_FAILED(rv)) {
+ if (NS_FAILED(rv)) {
NS_WARNING("Cannot create DBus Connection for DBus Thread!");
return false;
}
// Set which messages will be processed by this dbus connection.
// Since we are maintaining a single thread for all the DBus bluez
// signals we want, register all of them in this thread at startup.
// The event handler will sort the destinations out as needed.
- for(uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
+ for (uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
dbus_bus_add_match(mConnection,
DBUS_SIGNALS[i],
&err);
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
return false;
}
}
@@ -363,94 +360,81 @@ DBusThread::TearDownData()
bool
DBusThread::TearDownEventLoop()
{
MOZ_ASSERT(mConnection);
DBusError err;
dbus_error_init(&err);
- for(uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
+ for (uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
dbus_bus_remove_match(mConnection,
DBUS_SIGNALS[i],
&err);
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
}
}
return true;
}
-void*
-DBusThread::EventLoop(void *aPtr)
+void
+DBusThread::EventLoop()
{
- DBusThread* dbt = static_cast<DBusThread*>(aPtr);
- MOZ_ASSERT(dbt);
+ dbus_connection_set_watch_functions(mConnection, AddWatch,
+ RemoveWatch, ToggleWatch, this, NULL);
- dbus_connection_set_watch_functions(dbt->mConnection, AddWatch,
- RemoveWatch, ToggleWatch, aPtr, NULL);
-
- dbt->mIsRunning = true;
LOG("DBus Event Loop Starting\n");
while (1) {
- poll(dbt->mPollData.Elements(), dbt->mPollData.Length(), -1);
+ poll(mPollData.Elements(), mPollData.Length(), -1);
- for (uint32_t i = 0; i < dbt->mPollData.Length(); i++) {
- if (!dbt->mPollData[i].revents) {
+ for (uint32_t i = 0; i < mPollData.Length(); i++) {
+ if (!mPollData[i].revents) {
continue;
}
- if (dbt->mPollData[i].fd == dbt->mControlFdR.get()) {
+ if (mPollData[i].fd == mControlFdR.get()) {
char data;
- while (recv(dbt->mControlFdR.get(), &data, sizeof(char), MSG_DONTWAIT)
+ while (recv(mControlFdR.get(), &data, sizeof(char), MSG_DONTWAIT)
!= -1) {
switch (data) {
- case DBUS_EVENT_LOOP_EXIT:
- {
- LOG("DBus Event Loop Exiting\n");
- dbus_connection_set_watch_functions(dbt->mConnection,
- NULL, NULL, NULL, NULL, NULL);
- dbt->TearDownEventLoop();
- return NULL;
- }
- case DBUS_EVENT_LOOP_ADD:
- {
- HandleWatchAdd(dbt);
- break;
- }
- case DBUS_EVENT_LOOP_REMOVE:
- {
- HandleWatchRemove(dbt);
- break;
- }
+ case DBUS_EVENT_LOOP_EXIT:
+ LOG("DBus Event Loop Exiting\n");
+ dbus_connection_set_watch_functions(mConnection,
+ NULL, NULL, NULL, NULL, NULL);
+ TearDownEventLoop();
+ return;
+ case DBUS_EVENT_LOOP_ADD:
+ HandleWatchAdd(this);
+ break;
+ case DBUS_EVENT_LOOP_REMOVE:
+ HandleWatchRemove(this);
+ break;
}
}
} else {
- short events = dbt->mPollData[i].revents;
+ short events = mPollData[i].revents;
unsigned int flags = UnixEventsToDBusFlags(events);
- dbus_watch_handle(dbt->mWatchData[i], flags);
- dbt->mPollData[i].revents = 0;
+ dbus_watch_handle(mWatchData[i], flags);
+ mPollData[i].revents = 0;
// Break at this point since we don't know if the operation
// was destructive
break;
}
}
- while (dbus_connection_dispatch(dbt->mConnection) ==
+ while (dbus_connection_dispatch(mConnection) ==
DBUS_DISPATCH_DATA_REMAINS)
{}
}
}
bool
DBusThread::StartEventLoop()
{
- MutexAutoLock lock(mMutex);
- mIsRunning = false;
-
// socketpair opens two sockets for the process to communicate on.
// This is how android's implementation of the dbus event loop
// communicates with itself in relation to IPC signals. These
// sockets are contained sequentially in the same struct in the
// android code, but we break them out into class members here.
// Therefore we read into a local array and then copy.
int sockets[2];
@@ -469,112 +453,76 @@ DBusThread::StartEventLoop()
// push a null to the front of mWatchData since it has the control
// fd in the first slot of mPollData.
mWatchData.AppendElement((DBusWatch*)NULL);
if (!SetUpEventLoop()) {
TearDownData();
return false;
}
+ if (NS_FAILED(NS_NewNamedThread("DBus Poll",
+ getter_AddRefs(mThread),
+ NS_NewNonOwningRunnableMethod(this,
+ &DBusThread::EventLoop)))) {
+ NS_WARNING("Cannot create DBus Thread!");
+ return false;
+ }
LOG("DBus Thread Starting\n");
- pthread_create(&(mThread), NULL, DBusThread::EventLoop, this);
return true;
}
-void
+bool
DBusThread::StopEventLoop()
{
- MutexAutoLock lock(mMutex);
- if (mIsRunning) {
- char data = DBUS_EVENT_LOOP_EXIT;
- ssize_t wret = write(mControlFdW.get(), &data, sizeof(char));
- if(wret < 0) {
- LOG("Cannot write exit bit to DBus Thread!\n");
- }
- void *ret;
- LOG("DBus Thread Joining\n");
- pthread_join(mThread, &ret);
- LOG("DBus Thread Joined\n");
- TearDownData();
+ if (!mThread) {
+ return true;
+ }
+ char data = DBUS_EVENT_LOOP_EXIT;
+ ssize_t wret = write(mControlFdW.get(), &data, sizeof(char));
+ if(wret < 0) {
+ NS_ERROR("Cannot write exit flag to Dbus Thread!");
+ return false;
}
- mIsRunning = false;
-}
-
-bool
-DBusThread::IsEventLoopRunning()
-{
- MutexAutoLock lock(mMutex);
- return mIsRunning;
+ LOG("DBus Thread Joining\n");
+ nsCOMPtr<nsIThread> tmpThread;
+ mThread.swap(tmpThread);
+ if(NS_FAILED(tmpThread->Shutdown())) {
+ NS_WARNING("DBus thread shutdown failed!");
+ }
+ LOG("DBus Thread Joined\n");
+ TearDownData();
+ return true;
}
// Startup/Shutdown utility functions
-static void
-ConnectDBus(Monitor* aMonitor, bool* aSuccess)
-{
- if(sDBusThread) {
- NS_WARNING("Trying to start DBus Thread that is already currently running, skipping.");
- return;
- }
-
- sDBusThread = new DBusThread();
- *aSuccess = true;
- if(!sDBusThread->StartEventLoop())
- {
- *aSuccess = false;
- }
- {
- MonitorAutoLock lock(*aMonitor);
- lock.Notify();
- }
-}
-
-static void
-DisconnectDBus(Monitor* aMonitor, bool* aSuccess)
-{
- if(!sDBusThread) {
- NS_WARNING("Trying to shutdown DBus Thread that is not currently running, skipping.");
- return;
- }
-
- *aSuccess = true;
- sDBusThread->StopEventLoop();
- sDBusThread = NULL;
- {
- MonitorAutoLock lock(*aMonitor);
- lock.Notify();
- }
-}
-
bool
StartDBus()
{
- Monitor monitor("StartDBus.monitor");
- bool success;
- {
- MonitorAutoLock lock(monitor);
-
- XRE_GetIOMessageLoop()->PostTask(
- FROM_HERE,
- NewRunnableFunction(ConnectDBus, &monitor, &success));
- lock.Wait();
+ MOZ_ASSERT(!NS_IsMainThread());
+ if (sDBusThread) {
+ NS_WARNING("Trying to start DBus Thread that is already currently running, skipping.");
+ return true;
}
- return success;
+ nsAutoPtr<DBusThread> thread(new DBusThread());
+ if (!thread->StartEventLoop()) {
+ NS_WARNING("Cannot start DBus event loop!");
+ return false;
+ }
+ sDBusThread = thread;
+ return true;
}
bool
StopDBus()
{
- Monitor monitor("StopDBus.monitor");
- bool success;
- {
- MonitorAutoLock lock(monitor);
+ MOZ_ASSERT(!NS_IsMainThread());
+ if (!sDBusThread) {
+ return true;
+ }
- XRE_GetIOMessageLoop()->PostTask(
- FROM_HERE,
- NewRunnableFunction(DisconnectDBus, &monitor, &success));
- lock.Wait();
- }
- return success;
+ nsAutoPtr<DBusThread> thread(sDBusThread);
+ sDBusThread = nsnull;
+ return thread->StopEventLoop();
}
}
}
--- a/ipc/dbus/DBusUtils.cpp
+++ b/ipc/dbus/DBusUtils.cpp
@@ -33,129 +33,131 @@
#define BLUEZ_ERROR_IFC "org.bluez.Error"
namespace mozilla {
namespace ipc {
void
log_and_free_dbus_error(DBusError* err, const char* function, DBusMessage* msg)
{
- if(msg) {
+ if (msg) {
LOG("%s: D-Bus error in %s: %s (%s)", function,
dbus_message_get_member((msg)), (err)->name, (err)->message);
} else {
LOG("%s: D-Bus error: %s (%s)", __FUNCTION__,
(err)->name, (err)->message);
}
dbus_error_free((err));
}
typedef struct {
- void (*user_cb)(DBusMessage *, void *, void *);
+ DBusCallback user_cb;
void *user;
- void *nat;
} dbus_async_call_t;
void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
dbus_async_call_t *req = (dbus_async_call_t *)data;
DBusMessage *msg;
/* This is guaranteed to be non-NULL, because this function is called only
when once the remote method invokation returns. */
msg = dbus_pending_call_steal_reply(call);
if (msg) {
if (req->user_cb) {
// The user may not deref the message object.
- req->user_cb(msg, req->user, req->nat);
+ req->user_cb(msg, req->user);
}
dbus_message_unref(msg);
}
//dbus_message_unref(req->method);
dbus_pending_call_cancel(call);
dbus_pending_call_unref(call);
free(req);
}
+dbus_bool_t dbus_func_send_async(DBusConnection *conn,
+ DBusMessage *msg,
+ int timeout_ms,
+ void (*user_cb)(DBusMessage*,
+ void*),
+ void *user) {
+ dbus_async_call_t *pending;
+ dbus_bool_t reply = FALSE;
+
+ // Freed at end of dbus_func_args_async_callback (becomes "req")
+ pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
+ DBusPendingCall *call;
+
+ pending->user_cb = user_cb;
+ pending->user = user;
+
+ reply = dbus_connection_send_with_reply(conn, msg,
+ &call,
+ timeout_ms);
+ if (reply) {
+ dbus_pending_call_set_notify(call,
+ dbus_func_args_async_callback,
+ pending,
+ NULL);
+ }
+
+ if (msg) dbus_message_unref(msg);
+ return reply;
+}
+
static dbus_bool_t dbus_func_args_async_valist(DBusConnection *conn,
int timeout_ms,
- void (*user_cb)(DBusMessage *,
- void *,
+ void (*user_cb)(DBusMessage*,
void*),
void *user,
- void *nat,
const char *path,
const char *ifc,
const char *func,
int first_arg_type,
va_list args) {
- DBusMessage *msg = NULL;
- const char *name;
- dbus_async_call_t *pending;
- dbus_bool_t reply = FALSE;
-
+ DBusMessage *msg = NULL;
/* Compose the command */
msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
if (msg == NULL) {
LOG("Could not allocate D-Bus message object!");
goto done;
}
/* append arguments */
if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
LOG("Could not append argument to method call!");
goto done;
}
- /* Make the call. */
- pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
- if (pending) {
- DBusPendingCall *call;
-
- pending->user_cb = user_cb;
- pending->user = user;
- pending->nat = nat;
- //pending->method = msg;
-
- reply = dbus_connection_send_with_reply(conn, msg,
- &call,
- timeout_ms);
- if (reply == TRUE) {
- dbus_pending_call_set_notify(call,
- dbus_func_args_async_callback,
- pending,
- NULL);
- }
- }
-
+ return dbus_func_send_async(conn, msg, timeout_ms, user_cb, user);
done:
if (msg) dbus_message_unref(msg);
- return reply;
+ return FALSE;
}
dbus_bool_t dbus_func_args_async(DBusConnection *conn,
int timeout_ms,
- void (*reply)(DBusMessage *, void *, void*),
+ void (*reply)(DBusMessage *, void *),
void *user,
- void *nat,
const char *path,
const char *ifc,
const char *func,
int first_arg_type,
...) {
dbus_bool_t ret;
va_list lst;
va_start(lst, first_arg_type);
ret = dbus_func_args_async_valist(conn,
timeout_ms,
- reply, user, nat,
+ reply, user,
path, ifc, func,
first_arg_type, lst);
va_end(lst);
return ret;
}
// If err is NULL, then any errors will be LOG'd, and free'd and the reply
// will be NULL.
@@ -168,17 +170,16 @@ DBusMessage * dbus_func_args_timeout_val
DBusError *err,
const char *path,
const char *ifc,
const char *func,
int first_arg_type,
va_list args) {
DBusMessage *msg = NULL, *reply = NULL;
- const char *name;
bool return_error = (err != NULL);
if (!return_error) {
err = (DBusError*)malloc(sizeof(DBusError));
dbus_error_init(err);
}
/* Compose the command */
--- a/ipc/dbus/DBusUtils.h
+++ b/ipc/dbus/DBusUtils.h
@@ -45,59 +45,68 @@ public:
if (mMsg) dbus_message_unref(mMsg);
}
operator DBusMessage*() { return mMsg; }
DBusMessage* get() { return mMsg; }
private:
DBusMessage* mMsg;
};
+typedef void (*DBusCallback)(DBusMessage *, void *);
+
+
void log_and_free_dbus_error(DBusError* err,
const char* function,
DBusMessage* msg = NULL);
-dbus_bool_t dbus_func_args_async(DBusConnection *conn,
+
+dbus_bool_t dbus_func_send_async(DBusConnection* conn,
+ DBusMessage* msg,
int timeout_ms,
- void (*reply)(DBusMessage *, void *, void *),
- void *user,
- void *nat,
- const char *path,
- const char *ifc,
- const char *func,
+ DBusCallback user_cb,
+ void* user);
+
+dbus_bool_t dbus_func_args_async(DBusConnection* conn,
+ int timeout_ms,
+ DBusCallback reply,
+ void* user,
+ const char* path,
+ const char* ifc,
+ const char* func,
int first_arg_type,
...);
-DBusMessage * dbus_func_args(DBusConnection *conn,
- const char *path,
- const char *ifc,
- const char *func,
+DBusMessage* dbus_func_args(DBusConnection* conn,
+ const char* path,
+ const char* ifc,
+ const char* func,
int first_arg_type,
...);
-DBusMessage * dbus_func_args_error(DBusConnection *conn,
- DBusError *err,
- const char *path,
- const char *ifc,
- const char *func,
+DBusMessage* dbus_func_args_error(DBusConnection* conn,
+ DBusError* err,
+ const char* path,
+ const char* ifc,
+ const char* func,
int first_arg_type,
...);
-DBusMessage * dbus_func_args_timeout(DBusConnection *conn,
+DBusMessage* dbus_func_args_timeout(DBusConnection* conn,
int timeout_ms,
- const char *path,
- const char *ifc,
- const char *func,
+ const char* path,
+ const char* ifc,
+ const char* func,
int first_arg_type,
...);
-DBusMessage * dbus_func_args_timeout_valist(DBusConnection *conn,
+DBusMessage* dbus_func_args_timeout_valist(DBusConnection* conn,
int timeout_ms,
- DBusError *err,
- const char *path,
- const char *ifc,
- const char *func,
+ DBusError* err,
+ const char* path,
+ const char* ifc,
+ const char* func,
int first_arg_type,
va_list args);
}
}
#endif
--- a/ipc/dbus/RawDBusConnection.cpp
+++ b/ipc/dbus/RawDBusConnection.cpp
@@ -24,10 +24,10 @@ nsresult RawDBusConnection::EstablishDBu
return NS_ERROR_FAILURE;
}
dbus_connection_set_exit_on_disconnect(mConnection, FALSE);
return NS_OK;
}
void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
{
- if(ptr) dbus_connection_unref(ptr);
+ if (ptr) dbus_connection_unref(ptr);
}
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -20,18 +20,19 @@ EXPORT_LIBRARY = 1
##-----------------------------------------------------------------------------
## When you add IPDL files to a source directory, list the directory here.
##
IPDLDIRS = \
uriloader/exthandler \
dom/devicestorage \
dom/indexedDB/ipc \
+ dom/bluetooth/ipc \
dom/plugins/ipc \
- dom/ipc \
+ dom/ipc \
dom/sms/src/ipc \
dom/src/storage \
gfx/layers/ipc \
hal/sandbox \
ipc/testshell \
js/ipc \
layout/ipc \
netwerk/ipc \