Bug 740744: Asynchronous dbus events for bluetooth, Start/StopDiscovery and device event firing; r=bent sr=mrbkap

This commit is contained in:
Kyle Machulis 2012-07-17 20:41:54 -07:00
parent 7ce5477f9b
commit f8c0d08e82
38 changed files with 2577 additions and 686 deletions

View File

@ -517,6 +517,8 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
#ifdef MOZ_B2G_BT
#include "BluetoothManager.h"
#include "BluetoothAdapter.h"
#include "BluetoothDevice.h"
#include "BluetoothDeviceEvent.h"
#endif
#include "nsIDOMNavigatorSystemMessages.h"
@ -1671,7 +1673,11 @@ static nsDOMClassInfoData sClassInfoData[] = {
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,
@ -4484,6 +4490,15 @@ nsDOMClassInfo::Init()
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)

View File

@ -528,6 +528,8 @@ DOMCI_CLASS(CallEvent)
#ifdef MOZ_B2G_BT
DOMCI_CLASS(BluetoothManager)
DOMCI_CLASS(BluetoothAdapter)
DOMCI_CLASS(BluetoothDevice)
DOMCI_CLASS(BluetoothDeviceEvent)
#endif
DOMCI_CLASS(DOMError)

View File

@ -4,16 +4,25 @@
* 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)
@ -22,10 +31,16 @@ 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)
@ -36,29 +51,227 @@ 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)

View File

@ -8,18 +8,21 @@
#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
@ -29,17 +32,55 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothAdapter,
nsDOMEventTargetHelper)
static already_AddRefed<BluetoothAdapter>
Create(const nsCString& name);
Create(nsPIDOMWindow* aOwner, const nsAString& name);
void Notify(const BluetoothEvent& aParam);
protected:
nsCString mName;
void Notify(const BluetoothSignal& aParam);
nsIDOMEventTarget*
ToIDOMEventTarget() const
{
return static_cast<nsDOMEventTargetHelper*>(
const_cast<BluetoothAdapter*>(this));
}
nsISupports*
ToISupports() const
{
return ToIDOMEventTarget();
}
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

View File

@ -22,43 +22,8 @@ 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

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}
}
}
}

View File

@ -4,29 +4,23 @@
* 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"
@ -35,36 +29,16 @@ 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
@ -77,148 +51,149 @@ 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());
}
public:
ToggleBtResultTask(BluetoothManager* aManager,
nsIDOMDOMRequest* aReq,
bool aEnabled)
: BluetoothReplyRunnable(aReq),
mManagerPtr(aManager),
mEnabled(aEnabled)
{
}
NS_IMETHOD Run()
{
MOZ_ASSERT(!NS_IsMainThread());
~ToggleBtResultTask()
{
}
bool
ParseSuccessfulReply(jsval* aValue)
{
MOZ_ASSERT(NS_IsMainThread());
*aValue = JSVAL_VOID;
mManagerPtr->SetEnabledInternal(mEnabled);
return true;
}
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;
}
// return 1 if it's enabled, 0 if it's disabled, and -1 on error
int isEnabled = IsBluetoothEnabled();
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;
}
@ -226,32 +201,51 @@ 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();
}
@ -264,18 +258,28 @@ NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
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
}

View File

@ -10,14 +10,13 @@
#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
@ -33,17 +32,15 @@ public:
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

View File

@ -4,20 +4,13 @@
* 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__
#include "BluetoothService.h"
namespace mozilla {
namespace dom {
namespace bluetooth {
bool EnsureBluetoothInit();
int IsBluetoothEnabled();
int EnableBluetooth();
int DisableBluetooth();
USING_BLUETOOTH_NAMESPACE
BluetoothService*
BluetoothService::Create()
{
NS_WARNING("Bluetooth not implemented for this platform!");
return nsnull;
}
}
}
#endif

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -15,41 +15,58 @@ 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)
include $(topsrcdir)/config/rules.mk
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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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;
};
}
}
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -6,7 +6,31 @@
#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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -9,11 +9,11 @@
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);
};

View File

@ -19,36 +19,19 @@
#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 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 {
@ -229,15 +212,6 @@ SystemWorkerManager::Init()
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
@ -270,9 +244,7 @@ SystemWorkerManager::Shutdown()
#endif
StopRil();
#ifdef MOZ_B2G_BT
StopDBus();
#endif
mRILWorker = nsnull;
nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
if (wifi) {
@ -385,29 +357,6 @@ SystemWorkerManager::InitWifi(JSContext *cx)
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

View File

@ -45,8 +45,7 @@ private:
nsresult InitRIL(JSContext *cx);
nsresult InitWifi(JSContext *cx);
nsresult InitBluetooth(JSContext *cx);
nsCOMPtr<nsIWorkerHolder> mRILWorker;
nsCOMPtr<nsIWorkerHolder> mWifiWorker;

View File

@ -46,7 +46,6 @@
#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"
@ -62,7 +61,7 @@
#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
@ -131,14 +130,12 @@ struct DBusThread : public RawDBusConnection
~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
@ -173,25 +170,25 @@ AddWatch(DBusWatch *aWatch, void *aData)
// 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;
}
@ -205,20 +202,20 @@ 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;
}
@ -240,15 +237,15 @@ 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;
}
@ -258,20 +255,21 @@ HandleWatchAdd(DBusThread* aDbt)
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;
}
@ -284,7 +282,7 @@ static void HandleWatchRemove(DBusThread* aDbt) {
// 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;
}
@ -297,8 +295,7 @@ static void HandleWatchRemove(DBusThread* aDbt) {
// DBus Thread Implementation
DBusThread::DBusThread() : mMutex("DBusGonk.mMutex")
, mIsRunning(false)
DBusThread::DBusThread()
{
}
@ -311,7 +308,7 @@ bool
DBusThread::SetUpEventLoop()
{
// If we already have a connection, exit
if(mConnection) {
if (mConnection) {
return false;
}
@ -321,7 +318,7 @@ DBusThread::SetUpEventLoop()
// 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;
}
@ -330,7 +327,7 @@ DBusThread::SetUpEventLoop()
// 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);
@ -368,7 +365,7 @@ DBusThread::TearDownEventLoop()
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);
@ -380,61 +377,51 @@ DBusThread::TearDownEventLoop()
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)
{}
}
@ -443,9 +430,6 @@ DBusThread::EventLoop(void *aPtr)
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
@ -474,106 +458,70 @@ DBusThread::StartEventLoop()
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;
}
mIsRunning = false;
}
bool
DBusThread::IsEventLoopRunning()
{
MutexAutoLock lock(mMutex);
return mIsRunning;
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;
}
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);
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(DisconnectDBus, &monitor, &success));
lock.Wait();
MOZ_ASSERT(!NS_IsMainThread());
if (!sDBusThread) {
return true;
}
return success;
nsAutoPtr<DBusThread> thread(sDBusThread);
sDBusThread = nsnull;
return thread->StopEventLoop();
}
}

View File

@ -38,7 +38,7 @@ 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 {
@ -49,9 +49,8 @@ log_and_free_dbus_error(DBusError* err, const char* function, DBusMessage* msg)
}
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) {
@ -66,7 +65,7 @@ void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
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);
}
@ -77,23 +76,47 @@ void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
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);
@ -108,37 +131,16 @@ static dbus_bool_t dbus_func_args_async_valist(DBusConnection *conn,
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,
@ -150,7 +152,7 @@ dbus_bool_t dbus_func_args_async(DBusConnection *conn,
ret = dbus_func_args_async_valist(conn,
timeout_ms,
reply, user, nat,
reply, user,
path, ifc, func,
first_arg_type, lst);
va_end(lst);
@ -173,7 +175,6 @@ DBusMessage * dbus_func_args_timeout_valist(DBusConnection *conn,
va_list args) {
DBusMessage *msg = NULL, *reply = NULL;
const char *name;
bool return_error = (err != NULL);
if (!return_error) {

View File

@ -50,49 +50,58 @@ 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);

View File

@ -29,5 +29,5 @@ nsresult RawDBusConnection::EstablishDBusConnection() {
void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
{
if(ptr) dbus_connection_unref(ptr);
if (ptr) dbus_connection_unref(ptr);
}

View File

@ -25,8 +25,9 @@ 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 \