Bug 853221 - Patch 1: Distribute connection/pair status to BluetoothAdapter, r=echou
authorGina Yeh <gyeh@mozilla.com>
Fri, 02 Aug 2013 18:32:57 +0800
changeset 148691 989eeb2e71fffaeea5c8763ec918a5d66afb45ea
parent 148689 73dcf35e07cf2e2a3b2e76c3985a9c78093181bf
child 148692 cf744991c7e07ce67400c03b14e3a0c681aac460
push idunknown
push userunknown
push dateunknown
reviewersechou
bugs853221
milestone25.0a1
Bug 853221 - Patch 1: Distribute connection/pair status to BluetoothAdapter, r=echou
dom/bluetooth/BluetoothA2dpManager.cpp
dom/bluetooth/BluetoothA2dpManager.h
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/BluetoothHfpManager.cpp
dom/bluetooth/BluetoothHfpManager.h
dom/bluetooth/BluetoothService.cpp
dom/bluetooth/BluetoothUtils.cpp
dom/bluetooth/BluetoothUtils.h
dom/bluetooth/linux/BluetoothDBusService.cpp
--- a/dom/bluetooth/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/BluetoothA2dpManager.cpp
@@ -199,17 +199,18 @@ BluetoothA2dpManager::HandleSinkProperty
   MOZ_ASSERT(arr.Length() == 1);
 
   const nsString& name = arr[0].name();
   const BluetoothValue& value = arr[0].value();
   if (name.EqualsLiteral("Connected")) {
     // Indicates if a stream is setup to a A2DP sink on the remote device.
     MOZ_ASSERT(value.type() == BluetoothValue::Tbool);
     mA2dpConnected = value.get_bool();
-    NotifyStatusChanged();
+    NotifyConnectionStatusChanged();
+    DispatchConnectionStatusChanged();
   } else if (name.EqualsLiteral("Playing")) {
     // Indicates if a stream is active to a A2DP sink on the remote device.
     MOZ_ASSERT(value.type() == BluetoothValue::Tbool);
     mPlaying = value.get_bool();
   } else if (name.EqualsLiteral("State")) {
     MOZ_ASSERT(value.type() == BluetoothValue::TnsString);
     HandleSinkStateChanged(StatusStringToSinkState(value.get_nsString()));
   } else {
@@ -249,17 +250,26 @@ BluetoothA2dpManager::HandleSinkStateCha
   if (aState == SinkState::SINK_DISCONNECTED) {
     mDeviceAddress.Truncate();
   }
 
   mSinkState = aState;
 }
 
 void
-BluetoothA2dpManager::NotifyStatusChanged()
+BluetoothA2dpManager::DispatchConnectionStatusChanged()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  DispatchStatusChangedEvent(
+    NS_LITERAL_STRING(A2DP_STATUS_CHANGED_ID), mDeviceAddress, mA2dpConnected);
+}
+
+void
+BluetoothA2dpManager::NotifyConnectionStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Broadcast system message to Gaia
   NS_NAMED_LITERAL_STRING(type, BLUETOOTH_A2DP_STATUS_CHANGED_ID);
   InfallibleTArray<BluetoothNamedValue> parameters;
 
   BluetoothValue v = mA2dpConnected;
--- a/dom/bluetooth/BluetoothA2dpManager.h
+++ b/dom/bluetooth/BluetoothA2dpManager.h
@@ -67,22 +67,24 @@ public:
 
 private:
   BluetoothA2dpManager();
   bool Init();
 
   void HandleSinkStateChanged(SinkState aState);
   void HandleShutdown();
 
-  void NotifyStatusChanged();
+  void DispatchConnectionStatusChanged();
+  void NotifyConnectionStatusChanged();
+
+  nsString mDeviceAddress;
 
   // A2DP data member
   bool mA2dpConnected;
   bool mPlaying;
-  nsString mDeviceAddress;
   SinkState mSinkState;
 
   // AVRCP data member
   bool mAvrcpConnected;
   nsString mAlbum;
   nsString mArtist;
   nsString mTitle;
   uint32_t mDuration;
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -47,22 +47,36 @@ extern bool gBluetoothDebugFlag;
   using namespace mozilla::dom::bluetooth;
 
 #define KEY_LOCAL_AGENT  "/B2G/bluetooth/agent"
 #define KEY_REMOTE_AGENT "/B2G/bluetooth/remote_device_agent"
 #define KEY_MANAGER      "/B2G/bluetooth/manager"
 #define KEY_ADAPTER      "/B2G/bluetooth/adapter"
 
 /**
- * When connection status of Bluetooth profiles change, we'll notify observers
- * of following topics.
+ * When the connection status of a Bluetooth profile is changed, we'll notify
+ * observers which register the following topics.
  */
-#define BLUETOOTH_HFP_STATUS_CHANGED_ID      "bluetooth-hfp-status-changed"
-#define BLUETOOTH_SCO_STATUS_CHANGED_ID      "bluetooth-sco-status-changed"
-#define BLUETOOTH_A2DP_STATUS_CHANGED_ID     "bluetooth-a2dp-status-changed"
+#define BLUETOOTH_A2DP_STATUS_CHANGED_ID "bluetooth-a2dp-status-changed"
+#define BLUETOOTH_HFP_STATUS_CHANGED_ID  "bluetooth-hfp-status-changed"
+#define BLUETOOTH_SCO_STATUS_CHANGED_ID  "bluetooth-sco-status-changed"
+
+/**
+ * When the connection status of a Bluetooth profile is changed, we'll
+ * distribute one of the following events.
+ */
+#define A2DP_STATUS_CHANGED_ID               "a2dpstatuschanged"
+#define HFP_STATUS_CHANGED_ID                "hfpstatuschanged"
+#define SCO_STATUS_CHANGED_ID                "scostatuschanged"
+
+/**
+ * When the pair status of a Bluetooth device is changed, we'll distribute an
+ * event.
+ */
+#define PAIRED_STATUS_CHANGED_ID             "pairedstatuschanged"
 
 // Bluetooth address format: xx:xx:xx:xx:xx:xx (or xx_xx_xx_xx_xx_xx)
 #define BLUETOOTH_ADDRESS_LENGTH 17
 #define BLUETOOTH_ADDRESS_NONE   "00:00:00:00:00:00"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 enum BluetoothSocketType {
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -449,50 +449,67 @@ BluetoothHfpManager::Get()
   BluetoothHfpManager* manager = new BluetoothHfpManager();
   NS_ENSURE_TRUE(manager->Init(), nullptr);
 
   sBluetoothHfpManager = manager;
   return sBluetoothHfpManager;
 }
 
 void
-BluetoothHfpManager::NotifyStatusChanged(const char* aType)
+BluetoothHfpManager::DispatchConnectionStatusChanged(const nsAString& aType)
 {
-  // Broadcast system message to Gaia
+  MOZ_ASSERT(NS_IsMainThread());
+
+  bool status = false;
+  if (aType.EqualsLiteral(HFP_STATUS_CHANGED_ID)) {
+    status = IsConnected();
+  } else if (aType.EqualsLiteral(SCO_STATUS_CHANGED_ID)) {
+    status = IsScoConnected();
+  } else {
+    BT_WARNING("Wrong type for DispatchConnectionStatusChanged");
+    return;
+  }
+
+  DispatchStatusChangedEvent(aType, mDeviceAddress, status);
+}
+
+void
+BluetoothHfpManager::NotifyConnectionStatusChanged(const nsAString& aType)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
   BluetoothValue v;
   InfallibleTArray<BluetoothNamedValue> parameters;
-  nsAutoString type, name;
-  type = NS_ConvertUTF8toUTF16(aType);
-  name.AssignLiteral("connected");
-
-  if (type.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
+  nsString name = NS_LITERAL_STRING("connected");
+  if (aType.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
     v = IsConnected();
-  } else if (type.EqualsLiteral(BLUETOOTH_SCO_STATUS_CHANGED_ID)) {
+  } else if (aType.EqualsLiteral(BLUETOOTH_SCO_STATUS_CHANGED_ID)) {
     v = IsScoConnected();
   } else {
-    NS_WARNING("Wrong type for NotifyStatusChanged");
+    BT_WARNING("Wrong type for NotifyConnectionStatusChanged");
     return;
   }
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   name.AssignLiteral("address");
   v = mDeviceAddress;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
-  if (!BroadcastSystemMessage(type, parameters)) {
+  if (!BroadcastSystemMessage(aType, parameters)) {
     NS_WARNING("Failed to broadcast system message to settings");
   }
 
   // Notify Gecko observers
   nsCOMPtr<nsIObserverService> obs =
     do_GetService("@mozilla.org/observer-service;1");
   NS_ENSURE_TRUE_VOID(obs);
 
-  if (NS_FAILED(obs->NotifyObservers(this, aType, mDeviceAddress.get()))) {
-    NS_WARNING("Failed to notify bluetooth-sco-status-changed observsers!");
+  if (NS_FAILED(obs->NotifyObservers(this, NS_ConvertUTF16toUTF8(aType).get(),
+                                     mDeviceAddress.get()))) {
+    NS_WARNING("Failed to notify observsers!");
   }
 }
 
 void
 BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
 {
   nsString type, name;
   BluetoothValue v;
@@ -1477,17 +1494,18 @@ BluetoothHfpManager::OnConnectSuccess(Bl
     mRunnable = nullptr;
   }
 
   mFirstCKPD = true;
 
   // Cache device path for NotifySettings() since we can't get socket address
   // when a headset disconnect with us
   mSocket->GetAddress(mDeviceAddress);
-  NotifyStatusChanged(BLUETOOTH_HFP_STATUS_CHANGED_ID);
+  NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
+  DispatchConnectionStatusChanged(NS_LITERAL_STRING(HFP_STATUS_CHANGED_ID));
 
   ListenSco();
 
   BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
   NS_ENSURE_TRUE_VOID(a2dp);
   a2dp->Connect(mDeviceAddress);
 }
 
@@ -1532,17 +1550,18 @@ BluetoothHfpManager::OnDisconnect(Blueto
     // Do nothing when a listening server socket is closed.
     return;
   }
 
   mSocket = nullptr;
   DisconnectSco();
 
   Listen();
-  NotifyStatusChanged(BLUETOOTH_HFP_STATUS_CHANGED_ID);
+  NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
+  DispatchConnectionStatusChanged(NS_LITERAL_STRING(HFP_STATUS_CHANGED_ID));
   Reset();
 }
 
 void
 BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
@@ -1612,17 +1631,18 @@ BluetoothHfpManager::OnScoConnectSuccess
 {
   // For active connection request, we need to reply the DOMRequest
   if (mScoRunnable) {
     DispatchBluetoothReply(mScoRunnable,
                            BluetoothValue(true), EmptyString());
     mScoRunnable = nullptr;
   }
 
-  NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID);
+  NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_SCO_STATUS_CHANGED_ID));
+  DispatchConnectionStatusChanged(NS_LITERAL_STRING(SCO_STATUS_CHANGED_ID));
 
   mScoSocketStatus = mScoSocket->GetConnectionStatus();
 }
 
 void
 BluetoothHfpManager::OnScoConnectError()
 {
   if (mScoRunnable) {
@@ -1635,17 +1655,18 @@ BluetoothHfpManager::OnScoConnectError()
   ListenSco();
 }
 
 void
 BluetoothHfpManager::OnScoDisconnect()
 {
   if (mScoSocketStatus == SocketConnectionStatus::SOCKET_CONNECTED) {
     ListenSco();
-    NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID);
+    NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_SCO_STATUS_CHANGED_ID));
+    DispatchConnectionStatusChanged(NS_LITERAL_STRING(SCO_STATUS_CHANGED_ID));
   }
 }
 
 bool
 BluetoothHfpManager::IsConnected()
 {
   if (mSocket) {
     return mSocket->GetConnectionStatus() ==
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -112,18 +112,19 @@ private:
 
   bool Init();
   void Notify(const hal::BatteryInformation& aBatteryInfo);
   void Reset();
   void ResetCallArray();
   uint32_t FindFirstCall(uint16_t aState);
   uint32_t GetNumberOfCalls(uint16_t aState);
 
+  void DispatchConnectionStatusChanged(const nsAString& aType);
   void NotifyDialer(const nsAString& aCommand);
-  void NotifyStatusChanged(const char* aType);
+  void NotifyConnectionStatusChanged(const nsAString& aType);
 
   bool SendCommand(const char* aCommand, uint32_t aValue = 0);
   bool SendLine(const char* aMessage);
   void UpdateCIND(uint8_t aType, uint8_t aValue, bool aSend = true);
   void OnScoConnectSuccess();
   void OnScoConnectError();
   void OnScoDisconnect();
 
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -783,19 +783,19 @@ BluetoothService::Notify(const Bluetooth
   } else if (aData.name().EqualsLiteral("Authorize")) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 2,
       "Authorize: Wrong length of parameters");
     type.AssignLiteral("bluetooth-authorize");
   } else if (aData.name().EqualsLiteral("Cancel")) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 0,
       "Cancel: Wrong length of parameters");
     type.AssignLiteral("bluetooth-cancel");
-  } else if (aData.name().EqualsLiteral("PairedStatusChanged")) {
+  } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID)) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 1,
-      "PairedStatusChagned: Wrong length of parameters");
+      "pairedstatuschanged: Wrong length of parameters");
     type.AssignLiteral("bluetooth-pairedstatuschanged");
   } else {
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling service signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
     return;
   }
--- a/dom/bluetooth/BluetoothUtils.cpp
+++ b/dom/bluetooth/BluetoothUtils.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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 "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
 #include "BluetoothUtils.h"
 #include "jsapi.h"
 #include "mozilla/Scoped.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsIScriptContext.h"
 #include "nsISystemMessagesInternal.h"
@@ -168,9 +169,29 @@ ParseAtCommand(const nsACString& aAtComm
       begin = i + 1;
     }
   }
 
   nsCString tmp(nsDependentCSubstring(aAtCommand, begin));
   aRetValues.AppendElement(tmp);
 }
 
+void
+DispatchStatusChangedEvent(const nsAString& aType,
+                           const nsAString& aAddress,
+                           bool aStatus)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InfallibleTArray<BluetoothNamedValue> data;
+  data.AppendElement(
+    BluetoothNamedValue(NS_LITERAL_STRING("address"), nsString(aAddress)));
+  data.AppendElement(
+    BluetoothNamedValue(NS_LITERAL_STRING("status"), aStatus));
+
+  BluetoothSignal signal(nsString(aType), NS_LITERAL_STRING(KEY_ADAPTER), data);
+
+  BluetoothService* bs = BluetoothService::Get();
+  NS_ENSURE_TRUE_VOID(bs);
+  bs->DistributeSignal(signal);
+}
+
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/BluetoothUtils.h
+++ b/dom/bluetooth/BluetoothUtils.h
@@ -38,11 +38,16 @@ void
 DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
                        const BluetoothValue& aValue,
                        const nsAString& aErrorStr);
 
 void
 ParseAtCommand(const nsACString& aAtCommand, const int aStart,
                nsTArray<nsCString>& aRetValues);
 
+void
+DispatchStatusChangedEvent(const nsAString& aType,
+                           const nsAString& aDeviceAddress,
+                           bool aStatus);
+
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -462,16 +462,18 @@ GetIntCallback(DBusMessage* aMsg, void* 
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackIntMessage);
 }
 
 #ifdef DEBUG
 static void
 CheckForError(DBusMessage* aMsg, void *aParam, const nsAString& aError)
 {
+  NS_ENSURE_TRUE_VOID(aMsg);
+
   BluetoothValue v;
   nsAutoString replyError;
   UnpackVoidMessage(aMsg, nullptr, v, replyError);
   if (!v.get_bool()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aError).get());
   }
 }
 #endif
@@ -1479,26 +1481,37 @@ EventFilter(DBusConnection* aConn, DBusM
   } else if (dbus_message_is_signal(aMsg, DBUS_DEVICE_IFACE,
                                     "PropertyChanged")) {
     ParsePropertyChange(aMsg,
                         v,
                         errorStr,
                         sDeviceProperties,
                         ArrayLength(sDeviceProperties));
 
-    // Fire another task for sending system message of
-    // "bluetooth-pairedstatuschanged"
     BluetoothNamedValue& property = v.get_ArrayOfBluetoothNamedValue()[0];
     if (property.name().EqualsLiteral("Paired")) {
+      // Original approach: Broadcast system message of
+      // "bluetooth-pairedstatuschanged" from BluetoothService.
       BluetoothValue newValue(v);
       ToLowerCase(newValue.get_ArrayOfBluetoothNamedValue()[0].name());
-      BluetoothSignal signal(NS_LITERAL_STRING("PairedStatusChanged"),
+      BluetoothSignal signal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
                              NS_LITERAL_STRING(KEY_LOCAL_AGENT),
                              newValue);
       NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
+
+      // New approach: Dispatch event from BluetoothAdapter
+      bool status = property.value();
+      InfallibleTArray<BluetoothNamedValue> parameters;
+      parameters.AppendElement(
+        BluetoothNamedValue(NS_LITERAL_STRING("address"), signalPath));
+      parameters.AppendElement(
+        BluetoothNamedValue(NS_LITERAL_STRING("status"), status));
+      signal.path() = NS_LITERAL_STRING(KEY_ADAPTER);
+      signal.value() = parameters;
+      NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
     }
   } else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "AdapterAdded")) {
     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 manager path!");