Bug 761511: Patch 2 - Added BluetoothPropertyContainer base class and utility functions; r=mrbkap
authorKyle Machulis <kyle@nonpolynomial.com>
Tue, 31 Jul 2012 21:49:59 -0700
changeset 104185 e05666048b33a8aeb87779cf7a7823ee346ff2ce
parent 104184 f3f84816bd596b36840eadabffcddeed848533f2
child 104186 f94b5c54e94e5ed7c286b2bdfcbcd497bf7b2733
push idunknown
push userunknown
push dateunknown
reviewersmrbkap
bugs761511
milestone17.0a1
Bug 761511: Patch 2 - Added BluetoothPropertyContainer base class and utility functions; r=mrbkap
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/BluetoothPropertyContainer.cpp
dom/bluetooth/BluetoothPropertyContainer.h
dom/bluetooth/BluetoothReplyRunnable.cpp
dom/bluetooth/BluetoothReplyRunnable.h
dom/bluetooth/BluetoothService.h
dom/bluetooth/Makefile.in
dom/bluetooth/linux/BluetoothDBusService.cpp
dom/bluetooth/linux/BluetoothDBusService.h
dom/bluetooth/linux/BluetoothDBusUtils.cpp
ipc/dbus/DBusThread.cpp
ipc/dbus/DBusThread.h
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -20,11 +20,20 @@
 
 class nsCString;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSignal;
 typedef mozilla::Observer<BluetoothSignal> BluetoothSignalObserver;
 
+// Enums for object types, currently used for shared function lookups
+// (get/setproperty, etc...). Possibly discernable via dbus paths, but this
+// method is future-proofed for platform independence.
+enum BluetoothObjectType {
+  TYPE_MANAGER = 0,
+  TYPE_ADAPTER = 1,
+  TYPE_DEVICE = 2 
+};
+
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluetoothcommon_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothPropertyContainer.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+#include "BluetoothPropertyContainer.h"
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "nsIDOMDOMRequest.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+nsresult
+BluetoothPropertyContainer::GetProperties()
+{
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("Bluetooth service not available!");
+    return NS_ERROR_FAILURE;
+  }
+  nsRefPtr<BluetoothReplyRunnable> task = new GetPropertiesTask(this, NULL);
+  return bs->GetProperties(mObjectType, mPath, task);
+}
+
+nsresult
+BluetoothPropertyContainer::SetProperty(nsIDOMWindow* aOwner,
+                                        const BluetoothNamedValue& aProperty,
+                                        nsIDOMDOMRequest** aRequest)
+{
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("Bluetooth service not available!");
+    return NS_ERROR_FAILURE;
+  }
+  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(aOwner, getter_AddRefs(req));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOMRequest!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<BluetoothReplyRunnable> task = new BluetoothVoidReplyRunnable(req);
+  
+  rv = bs->SetProperty(mObjectType, mPath, aProperty, task);
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  req.forget(aRequest);
+  return NS_OK;
+}
+
+
+bool
+BluetoothPropertyContainer::GetPropertiesTask::ParseSuccessfulReply(jsval* aValue)
+{
+  *aValue = JSVAL_VOID;
+  BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
+  if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
+    NS_WARNING("Not a BluetoothNamedValue array!");
+    return false;
+  }
+  const InfallibleTArray<BluetoothNamedValue>& values =
+    mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
+  for (uint32_t i = 0; i < values.Length(); ++i) {
+    mPropObjPtr->SetPropertyByValue(values[i]);
+  }
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothPropertyContainer.h
@@ -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/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothpropertyobject_h__
+#define mozilla_dom_bluetooth_bluetoothpropertyobject_h__
+
+#include "BluetoothCommon.h"
+#include "BluetoothReplyRunnable.h"
+#include "mozilla/RefPtr.h"
+
+class nsIDOMDOMRequest;
+class nsIDOMWindow;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothNamedValue;
+
+class BluetoothPropertyContainer
+{
+public:
+  nsresult GetProperties();
+  nsresult SetProperty(nsIDOMWindow* aOwner,
+                       const BluetoothNamedValue& aProperty,
+                       nsIDOMDOMRequest** aRequest);
+  virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) = 0;
+  nsString GetPath()
+  {
+    return mPath;
+  }
+
+  // Compatibility with nsRefPtr to make sure we don't hold a weakptr to
+  // ourselves
+  virtual nsrefcnt AddRef() = 0;
+  virtual nsrefcnt Release() = 0;
+
+protected:
+  BluetoothPropertyContainer(BluetoothObjectType aType) :
+    mObjectType(aType)
+  {}
+
+  ~BluetoothPropertyContainer()
+  {}
+  
+  class GetPropertiesTask : public BluetoothReplyRunnable
+  {
+  public:
+    GetPropertiesTask(BluetoothPropertyContainer* aPropObj, nsIDOMDOMRequest* aReq) :
+      BluetoothReplyRunnable(aReq),
+      mPropObjPtr(aPropObj)
+    {
+      MOZ_ASSERT(aReq && aPropObj);
+    }
+
+    virtual bool ParseSuccessfulReply(jsval* aValue);
+    
+    void
+    ReleaseMembers()
+    {
+      BluetoothReplyRunnable::ReleaseMembers();
+      mPropObjPtr = nullptr;
+    }
+    
+  private:
+    BluetoothPropertyContainer* mPropObjPtr;    
+  };
+
+  nsString mPath;
+  BluetoothObjectType mObjectType;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -2,18 +2,16 @@
 /* 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");
--- a/dom/bluetooth/BluetoothReplyRunnable.h
+++ b/dom/bluetooth/BluetoothReplyRunnable.h
@@ -4,20 +4,19 @@
  * 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 "nsIDOMDOMRequest.h"
 #include "jsapi.h"
 
-class nsIDOMDOMRequest;
-
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothReply;
 
 class BluetoothReplyRunnable : public nsRunnable
 {
 public:
   NS_DECL_NSIRUNNABLE
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -138,16 +138,60 @@ public:
   /** 
    * 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;
 
+  /** 
+   * Fetches the propertes for the specified object
+   *
+   * @param aType Type of the object (see BluetoothObjectType in BluetoothCommon.h)
+   * @param aPath Path of the object
+   * @param aRunnable Runnable to return to after receiving callback
+   *
+   * @return NS_OK on function run, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult
+  GetProperties(BluetoothObjectType aType,
+                const nsAString& aPath,
+                BluetoothReplyRunnable* aRunnable) = 0;
+
+  /** 
+   * Set a property for the specified object
+   *
+   * @param aPath Path to the object
+   * @param aPropName Name of the property
+   * @param aValue Boolean value
+   * @param aRunnable Runnable to run on async reply
+   *
+   * @return NS_OK if property is set correctly, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult
+  SetProperty(BluetoothObjectType aType,
+              const nsAString& aPath,
+              const BluetoothNamedValue& aValue,
+              BluetoothReplyRunnable* aRunnable) = 0;
+
+  /** 
+   * Get the path of a device
+   *
+   * @param aAdapterPath Path to the Adapter that's communicating with the device
+   * @param aDeviceAddress Device address (XX:XX:XX:XX:XX:XX format)
+   * @param aDevicePath Return value of path
+   *
+   * @return True if path set correctly, false otherwise
+   */
+  virtual bool
+  GetDevicePath(const nsAString& aAdapterPath,
+                const nsAString& aDeviceAddress,
+                nsAString& aDevicePath) = 0;
+
 protected:
   BluetoothService()
   {
     mBluetoothSignalObserverTable.Init();
   }
 
   virtual ~BluetoothService()
   {
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -30,16 +30,17 @@ include $(topsrcdir)/dom/dom-config.mk
 CPPSRCS += \
   BluetoothService.cpp \
   BluetoothManager.cpp \
   BluetoothAdapter.cpp \
   BluetoothDevice.cpp \
   BluetoothDeviceEvent.cpp \
   BluetoothPropertyEvent.cpp \
   BluetoothReplyRunnable.cpp \
+  BluetoothPropertyContainer.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothManager.idl \
   nsIDOMBluetoothAdapter.idl \
   nsIDOMBluetoothDevice.idl \
   nsIDOMBluetoothDeviceEvent.idl \
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -52,28 +52,29 @@ USING_BLUETOOTH_NAMESPACE
 #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_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager"
 #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[] = {
+static Properties sDeviceProperties[] = {
   {"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},
@@ -83,31 +84,42 @@ static Properties remote_device_properti
   {"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[] = {
+static Properties sAdapterProperties[] = {
   {"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[] =
+static Properties sManagerProperties[] = {
+  {"Adapters", DBUS_TYPE_ARRAY},
+};
+
+static const char* sBluetoothDBusIfaces[] =
+{
+  DBUS_MANAGER_IFACE,
+  DBUS_ADAPTER_IFACE,
+  DBUS_DEVICE_IFACE
+};
+
+static const char* sBluetoothDBusSignals[] =
 {
   "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'",
@@ -128,17 +140,16 @@ public:
   {
     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,
@@ -171,78 +182,89 @@ DispatchBluetoothReply(BluetoothReplyRun
     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)
+UnpackObjectPathMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                        nsAString& aErrorStr)
 {
-  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)) {
+  if (!IsDBusMessageError(aMsg, aErrorStr)) {
     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);
+        aErrorStr = NS_ConvertUTF8toUTF16(err.message);
         LOG_AND_FREE_DBUS_ERROR(&err);
       }
     } else {
-      v = NS_ConvertUTF8toUTF16(object_path);
+      aValue = NS_ConvertUTF8toUTF16(object_path);
     }
   }
-  DispatchBluetoothReply(replyRunnable, v, replyError);
 }
 
+typedef void (*UnpackFunc)(DBusMessage*, BluetoothValue&, nsAString&);
+
 void
-GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable,
+                UnpackFunc aFunc)
 {
   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) &&
+  aFunc(aMsg, v, replyError);
+  DispatchBluetoothReply(replyRunnable, v, replyError);  
+}
+
+void
+GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackObjectPathMessage);
+}
+
+void
+UnpackVoidMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                  nsAString& aErrorStr)
+{
+  DBusError err;
+  dbus_error_init(&err);
+  if (!IsDBusMessageError(aMsg, aErrorStr) &&
       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);
+      aErrorStr = NS_ConvertUTF8toUTF16(err.message);
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
-  DispatchBluetoothReply(replyRunnable, v, replyError);  
+}
+
+void
+GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackVoidMessage);
 }
 
 bool
 GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
-            int aPropertiesTypeLen, int* aPropIndex,
+            int aPropertyTypeLen, 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) {    
@@ -251,23 +273,23 @@ GetProperty(DBusMessageIter aIter, Prope
 
   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++) {
+  for (i = 0; i < aPropertyTypeLen; i++) {
     if (!strncmp(property, aPropertyTypes[i].name, strlen(property))) {      
       break;
     }
   }
 
-  if (i == aPropertiesTypeLen) {
+  if (i == aPropertyTypeLen) {
     return false;
   }
 
   nsString propertyName;
   propertyName.AssignASCII(aPropertyTypes[i].name);
   *aPropIndex = i;
 
   dbus_message_iter_recurse(&aIter, &prop_val);
@@ -305,72 +327,151 @@ GetProperty(DBusMessageIter aIter, Prope
           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 {
+        // This happens when the array is 0-length. Apparently we get a
+        // DBUS_TYPE_INVALID type.
+        propertyValue = InfallibleTArray<nsString>();
         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, 
+ParseProperties(DBusMessageIter* aIter,
+                BluetoothValue& aValue,
+                nsAString& aErrorStr,
                 Properties* aPropertyTypes,
-                const int aPropertiesTypeLen,
-                InfallibleTArray<BluetoothNamedValue>& aProperties)
+                const int aPropertyTypeLen)
 {
   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);
-
+  InfallibleTArray<BluetoothNamedValue> props;
   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)) {
+    if (!GetProperty(dict_entry, aPropertyTypes, aPropertyTypeLen, &prop_index,
+                     props)) {
+      aErrorStr.AssignLiteral("Can't Create Property!");
       NS_WARNING("Can't create property!");
       return;
     }
   } while (dbus_message_iter_next(&dict));
+
+  aValue = props;
+}
+
+void UnpackPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                             nsAString& aErrorStr, Properties* aPropertyTypes,
+                             const int aPropertyTypeLen)
+{
+  if (!IsDBusMessageError(aMsg, aErrorStr) &&
+      dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
+    DBusMessageIter iter;
+    if (!dbus_message_iter_init(aMsg, &iter)) {
+      aErrorStr.AssignLiteral("Cannot create dbus message iter!");
+    } else {
+      ParseProperties(&iter, aValue, aErrorStr, aPropertyTypes,
+                      aPropertyTypeLen);
+    }
+  }
+}
+
+void UnpackAdapterPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                                    nsAString& aErrorStr)
+{
+  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+                          sAdapterProperties,
+                          ArrayLength(sAdapterProperties));
+}
+
+void UnpackDevicePropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                                    nsAString& aErrorStr)
+{
+  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+                          sDeviceProperties,
+                          ArrayLength(sDeviceProperties));
+}
+
+void UnpackManagerPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                                    nsAString& aErrorStr)
+{
+  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+                          sManagerProperties,
+                          ArrayLength(sManagerProperties));
 }
 
 void
-ParsePropertyChange(DBusMessage* aMsg, Properties* aPropertyTypes,
-                    const int aPropertiesTypeLen,
-                    InfallibleTArray<BluetoothNamedValue>& aProperties)
+GetManagerPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackManagerPropertiesMessage);
+}
+
+void
+GetAdapterPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackAdapterPropertiesMessage);
+}
+
+void
+GetDevicePropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackDevicePropertiesMessage);
+}
+
+static DBusCallback sBluetoothDBusPropCallbacks[] =
+{
+  GetManagerPropertiesCallback,
+  GetAdapterPropertiesCallback,
+  GetDevicePropertiesCallback
+};
+
+MOZ_STATIC_ASSERT(sizeof(sBluetoothDBusPropCallbacks) == sizeof(sBluetoothDBusIfaces),
+  "DBus Property callback array and DBus interface array must be same size");
+
+void
+ParsePropertyChange(DBusMessage* aMsg, BluetoothValue& aValue,
+                    nsAString& aErrorStr, Properties* aPropertyTypes,
+                    const int aPropertyTypeLen)
 {
   DBusMessageIter iter;
   DBusError err;
   int prop_index = -1;
+  InfallibleTArray<BluetoothNamedValue> props;
   
   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)) {
+  if (!GetProperty(iter, aPropertyTypes, aPropertyTypeLen,
+                   &prop_index, props)) {
     NS_WARNING("Can't get property!");
+    aErrorStr.AssignLiteral("Can't get property!");
+    return;
   }
+  aValue = props;
 }
 
 // Called by dbus during WaitForAndDispatchEventNative()
 // This function is called on the IOThread
 static
 DBusHandlerResult
 EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
 {
@@ -387,72 +488,100 @@ EventFilter(DBusConnection* aConn, DBusM
     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));
+  nsString errorStr;
   BluetoothValue v;
   
   if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceFound")) {
 
     DBusMessageIter iter;
 
     if (!dbus_message_iter_init(aMsg, &iter)) {
       NS_WARNING("Can't create iterator!");
       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
-    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;
+                      v,
+                      errorStr,
+                      sDeviceProperties,
+                      ArrayLength(sDeviceProperties));
+      if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue)
+      {
+        // The DBus DeviceFound message actually passes back a key value object
+        // with the address as the key and the rest of the device properties as
+        // a dict value. After we parse out the properties, we need to go back
+        // and add the address to the ipdl dict we've created to make sure we
+        // have all of the information to correctly build the device.
+        v.get_ArrayOfBluetoothNamedValue()
+          .AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
+                                             NS_ConvertUTF8toUTF16(addr)));
+      }
     } else {
-      NS_WARNING("DBus iterator not as long as expected!");
+      errorStr.AssignLiteral("DBus device found message structure not 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);
+      errorStr.AssignLiteral("Cannot parse device address!");
     }
     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);
+      errorStr.AssignLiteral("Cannot parse device path!");
     }
     v = NS_ConvertUTF8toUTF16(str);
   } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "PropertyChanged")) {
-    InfallibleTArray<BluetoothNamedValue> value;
+    ParsePropertyChange(aMsg,
+                        v,
+                        errorStr,
+                        sAdapterProperties,
+                        ArrayLength(sAdapterProperties));
+  } else if (dbus_message_is_signal(aMsg, DBUS_DEVICE_IFACE, "PropertyChanged")) {
+    ParsePropertyChange(aMsg,
+                        v,
+                        errorStr,
+                        sDeviceProperties,
+                        ArrayLength(sDeviceProperties));
+  } else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "PropertyChanged")) {
     ParsePropertyChange(aMsg,
-                        (Properties*)&adapter_properties,
-                        ArrayLength(adapter_properties),
-                        value);
-    NS_ASSERTION(value.Length() != 0, "Properties returned empty!");
-    v = value;
+                        v,
+                        errorStr,
+                        sManagerProperties,
+                        ArrayLength(sManagerProperties));
+  } else {
+#ifdef DEBUG
+    nsCAutoString signalStr;
+    signalStr += dbus_message_get_member(aMsg);
+    signalStr += " Signal not handled!";
+    NS_WARNING(signalStr.get());
+#endif
+  }
+
+  if (!errorStr.IsEmpty()) {
+    NS_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   }
 
   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!");
@@ -572,8 +701,136 @@ BluetoothDBusService::StopDiscoveryInter
 }
  
 nsresult
 BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
                                              BluetoothReplyRunnable* aRunnable)
 {
   return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
 }
+
+nsresult
+BluetoothDBusService::GetProperties(BluetoothObjectType aType,
+                                    const nsAString& aPath,
+                                    BluetoothReplyRunnable* aRunnable)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+  MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusIfaces));
+  MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusPropCallbacks));
+  
+  const char* interface = sBluetoothDBusIfaces[aType];
+  DBusCallback callback = sBluetoothDBusPropCallbacks[aType];
+  
+  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+  if (!dbus_func_args_async(mConnection,
+                            1000,
+                            callback,
+                            (void*)aRunnable,
+                            NS_ConvertUTF16toUTF8(aPath).get(),
+                            interface,
+                            "GetProperties",
+                            DBUS_TYPE_INVALID)) {
+    NS_WARNING("Could not start async function!");
+    return NS_ERROR_FAILURE;
+  }
+  runnable.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::SetProperty(BluetoothObjectType aType,
+                                  const nsAString& aPath,
+                                  const BluetoothNamedValue& aValue,
+                                  BluetoothReplyRunnable* aRunnable)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+  MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusIfaces));
+  const char* interface = sBluetoothDBusIfaces[aType];
+
+  /* Compose the command */
+  DBusMessage* msg = dbus_message_new_method_call("org.bluez",
+                                                  NS_ConvertUTF16toUTF8(aPath).get(),
+                                                  interface,
+                                                  "SetProperty");
+
+  if (!msg) {
+    NS_WARNING("Could not allocate D-Bus message object!");
+    return NS_ERROR_FAILURE;
+  }
+
+  const char* propName = NS_ConvertUTF16toUTF8(aValue.name()).get();
+  if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &propName, DBUS_TYPE_INVALID)) {
+    NS_WARNING("Couldn't append arguments to dbus message!");
+    return NS_ERROR_FAILURE;
+  }
+  
+  int type;
+  int tmp_int;
+  void* val;
+  nsCString str;
+  if (aValue.value().type() == BluetoothValue::Tuint32_t) {
+    tmp_int = aValue.value().get_uint32_t();
+    val = &tmp_int;
+    type = DBUS_TYPE_UINT32;
+  } else if (aValue.value().type() == BluetoothValue::TnsString) {
+    str = NS_ConvertUTF16toUTF8(aValue.value().get_nsString());
+    val = (void*)str.get();
+    type = DBUS_TYPE_STRING;
+  } else if (aValue.value().type() == BluetoothValue::Tbool) {
+    tmp_int = aValue.value().get_bool() ? 1 : 0;
+    val = &(tmp_int);
+    type = DBUS_TYPE_BOOLEAN;
+  } else {
+    NS_WARNING("Property type not handled!");
+    dbus_message_unref(msg);
+    return NS_ERROR_FAILURE;
+  }
+  
+  DBusMessageIter value_iter, iter;
+  dbus_message_iter_init_append(msg, &iter);
+  char var_type[2] = {(char)type, '\0'};
+  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, var_type, &value_iter) ||
+      !dbus_message_iter_append_basic(&value_iter, type, val) ||
+      !dbus_message_iter_close_container(&iter, &value_iter)) {
+    NS_WARNING("Could not append argument to method call!");
+    dbus_message_unref(msg);
+    return NS_ERROR_FAILURE;
+  }
+  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+  // msg is unref'd as part of dbus_func_send_async 
+  if (!dbus_func_send_async(mConnection,
+                            msg,
+                            1000,
+                            GetVoidCallback,
+                            (void*)aRunnable)) {
+    NS_WARNING("Could not start async function!");
+    return NS_ERROR_FAILURE;
+  }
+  runnable.forget();
+  return NS_OK;
+}
+
+nsString
+GetObjectPathFromAddress(const nsAString& aAdapterPath,
+                         const nsAString& aDeviceAddress)
+{
+  // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1,
+  // and the adapter path would be the first part of the object path, accoring
+  // to the example above, it's /org/bluez/2906/hci0.
+  nsString devicePath(aAdapterPath);
+  devicePath.AppendLiteral("/dev_");
+  devicePath.Append(aDeviceAddress);
+  devicePath.ReplaceChar(':', '_');
+  return devicePath;
+}
+
+bool
+BluetoothDBusService::GetDevicePath(const nsAString& aAdapterPath,
+                                    const nsAString& aDeviceAddress,
+                                    nsAString& aDevicePath)
+{
+  aDevicePath = GetObjectPathFromAddress(aAdapterPath, aDeviceAddress);
+  return true;
+}
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -11,74 +11,53 @@
 #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.
+ * BluetoothDBusService is the implementation of BluetoothService for DBus on
+ * linux/android/B2G. Function comments are in BluetoothService.h
  */
 
 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);
+  virtual nsresult
+  GetProperties(BluetoothObjectType aType,
+                const nsAString& aPath,
+                BluetoothReplyRunnable* aRunnable);
+  virtual nsresult
+  SetProperty(BluetoothObjectType aType,
+              const nsAString& aPath,
+              const BluetoothNamedValue& aValue,
+              BluetoothReplyRunnable* aRunnable);
+  virtual bool
+  GetDevicePath(const nsAString& aAdapterPath,
+                const nsAString& aDeviceAddress,
+                nsAString& aDevicePath);
 
 private:
+  nsresult SendGetPropertyMessage(const nsAString& aPath,
+                                  const char* aInterface,
+                                  void (*aCB)(DBusMessage *, void *),
+                                  BluetoothReplyRunnable* aRunnable);
   nsresult SendDiscoveryMessage(const nsAString& aAdapterPath,
                                 const char* aMessageName,
                                 BluetoothReplyRunnable* aRunnable);
+  nsresult SendSetPropertyMessage(const nsString& aPath, const char* aInterface,
+                                  const BluetoothNamedValue& aValue,
+                                  BluetoothReplyRunnable* aRunnable);
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/linux/BluetoothDBusUtils.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusUtils.cpp
@@ -165,17 +165,17 @@ EventFilter(DBusConnection *aConn, DBusM
   }
 
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 nsresult
 StartBluetoothConnection()
 {
-  if(sDBusConnection) {
+  if (sDBusConnection) {
     NS_WARNING("DBusConnection already established, skipping");
     return NS_OK;    
   }
   sBluetoothEventObserverTable = new BluetoothEventObserverTable();
   sBluetoothEventObserverTable->Init(100);
 
   sDBusConnection = new RawDBusConnection();
   sDBusConnection->EstablishDBusConnection();
@@ -188,17 +188,17 @@ StartBluetoothConnection()
   }
 
   return NS_OK;
 }
 
 nsresult
 StopBluetoothConnection()
 {
-  if(!sDBusConnection) {
+  if (!sDBusConnection) {
     NS_WARNING("DBusConnection does not exist, nothing to stop, skipping.");
     return NS_OK;
   }
   dbus_connection_remove_filter(sDBusConnection->mConnection, EventFilter, NULL);
   sDBusConnection = NULL;
   sBluetoothEventObserverTable->Clear();
   sBluetoothEventObserverTable = NULL;
   return NS_OK;
--- a/ipc/dbus/DBusThread.cpp
+++ b/ipc/dbus/DBusThread.cpp
@@ -77,17 +77,16 @@ enum {
   DBUS_EVENT_LOOP_REMOVE = 3,
 } DBusEventTypes;
 
 // Signals that the DBus thread should listen for. Needs to include
 // all signals any DBus observer object may need.
 
 static const char* 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'"
--- a/ipc/dbus/DBusThread.h
+++ b/ipc/dbus/DBusThread.h
@@ -7,18 +7,16 @@
 #ifndef mozilla_ipc_dbus_gonk_dbusthread_h__
 #define mozilla_ipc_dbus_gonk_dbusthread_h__
 
 struct DBusMessage;
 
 namespace mozilla {
 namespace ipc {
 
-class nsCString;
-
 /** 
  * Starts the DBus thread, which handles returning signals to objects
  * that call asynchronous functions. This should be called from the
  * main thread at startup.
  *
  * @return True on thread starting correctly, false otherwise
  */
 bool StartDBus();