Bug 906305 - Patch 2: Make parameter service UUID of Connect() optional, r=echou, sr=mrbkap
authorGina Yeh <gyeh@mozilla.com>
Fri, 06 Sep 2013 19:19:46 +0800
changeset 158785 ef9b729c38a1253accb6baa87f402046994bb40c
parent 158784 ffd9e8e157dd50d3aec572adc8a2be658d56da9a
child 158786 585da14f78e27c3f9b7180d6c5c651b074eb786e
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechou, mrbkap
bugs906305
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 906305 - Patch 2: Make parameter service UUID of Connect() optional, r=echou, sr=mrbkap
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothAdapter.h
dom/bluetooth/BluetoothService.h
dom/bluetooth/BluetoothSocket.cpp
dom/bluetooth/BluetoothSocketObserver.h
dom/bluetooth/BluetoothUuid.cpp
dom/bluetooth/BluetoothUuid.h
dom/bluetooth/ipc/BluetoothParent.cpp
dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
dom/bluetooth/ipc/BluetoothServiceChildProcess.h
dom/bluetooth/ipc/PBluetooth.ipdl
dom/bluetooth/linux/BluetoothDBusService.cpp
dom/bluetooth/linux/BluetoothDBusService.h
dom/bluetooth/moz.build
dom/webidl/BluetoothAdapter.webidl
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -466,17 +466,17 @@ BluetoothAdapter::SetDiscoverableTimeout
     return FirePropertyAlreadySet(GetOwner(), aRv);
   }
   BluetoothValue value(aDiscoverableTimeout);
   BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value);
   return SetProperty(GetOwner(), property, aRv);
 }
 
 already_AddRefed<DOMRequest>
-BluetoothAdapter::GetConnectedDevices(uint16_t aProfileId, ErrorResult& aRv)
+BluetoothAdapter::GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
@@ -485,17 +485,17 @@ BluetoothAdapter::GetConnectedDevices(ui
   nsRefPtr<BluetoothReplyRunnable> results =
     new GetDevicesTask(this, request);
 
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
-  nsresult rv = bs->GetConnectedDevicePropertiesInternal(aProfileId, results);
+  nsresult rv = bs->GetConnectedDevicePropertiesInternal(aServiceUuid, results);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
@@ -659,58 +659,76 @@ BluetoothAdapter::SetPairingConfirmation
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
-BluetoothAdapter::Connect(const nsAString& aDeviceAddress,
-                          uint16_t aProfileId, ErrorResult& aRv)
+BluetoothAdapter::Connect(BluetoothDevice& aDevice,
+                          const Optional<short unsigned int>& aServiceUuid,
+                          ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
     new BluetoothVoidReplyRunnable(request);
 
+  nsAutoString address;
+  aDevice.GetAddress(address);
+  uint32_t deviceClass = aDevice.Class();
+  uint16_t serviceUuid = 0;
+  if (aServiceUuid.WasPassed()) {
+    serviceUuid = aServiceUuid.Value();
+  }
+
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
-  bs->Connect(aDeviceAddress, aProfileId, results);
+  bs->Connect(address, deviceClass, serviceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
-BluetoothAdapter::Disconnect(uint16_t aProfileId, ErrorResult& aRv)
+BluetoothAdapter::Disconnect(BluetoothDevice& aDevice,
+                             const Optional<short unsigned int>& aServiceUuid,
+                             ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
     new BluetoothVoidReplyRunnable(request);
 
+  nsAutoString address;
+  aDevice.GetAddress(address);
+  uint16_t serviceUuid = 0;
+  if (aServiceUuid.WasPassed()) {
+    serviceUuid = aServiceUuid.Value();
+  }
+
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
-  bs->Disconnect(aProfileId, results);
+  bs->Disconnect(address, serviceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
                            nsIDOMBlob* aBlob, ErrorResult& aRv)
 {
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -110,22 +110,24 @@ public:
   already_AddRefed<DOMRequest>
     SetPairingConfirmation(const nsAString& aDeviceAddress, bool aConfirmation,
                            ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
                      ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-    Connect(const nsAString& aDeviceAddress, uint16_t aProfile,
-            ErrorResult& aRv);
+    Connect(BluetoothDevice& aDevice,
+            const Optional<short unsigned int>& aServiceUuid, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
-    Disconnect(uint16_t aProfile, ErrorResult& aRv);
+    Disconnect(BluetoothDevice& aDevice,
+               const Optional<short unsigned int>& aServiceUuid,
+               ErrorResult& aRv);
   already_AddRefed<DOMRequest>
-    GetConnectedDevices(uint16_t aProfile, ErrorResult& aRv);
+    GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
     SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob,
              ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     ConfirmReceivingFile(const nsAString& aDeviceAddress, bool aConfirmation,
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -134,17 +134,17 @@ public:
 
   /**
    * Returns the properties of connected devices regarding to specific profile,
    * implemented via a platform specific methood.
    *
    * @return NS_OK on success, NS_ERROR_FAILURE otherwise
    */
   virtual nsresult
-  GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
+  GetConnectedDevicePropertiesInternal(uint16_t aServiceUuid,
                                        BluetoothReplyRunnable* aRunnable) = 0;
 
   /**
    * Stop device discovery (platform specific implementation)
    *
    * @return NS_OK if discovery stopped correctly, false otherwise
    */
   virtual nsresult
@@ -228,25 +228,25 @@ public:
   SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey,
                      BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual bool
   SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm,
                                  BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
-  Connect(const nsAString& aDeviceAddress,
-          uint16_t aProfileId,
+  Connect(const nsAString& aDeviceAddress, uint32_t aCod, uint16_t aServiceUuid,
           BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
-  Disconnect(uint16_t aProfileId, BluetoothReplyRunnable* aRunnable) = 0;
+  Disconnect(const nsAString& aDeviceAddress, uint16_t aServiceUuid,
+             BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual bool
-  IsConnected(uint16_t aProfileId) = 0;
+  IsConnected(uint16_t aServiceUuid) = 0;
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
--- a/dom/bluetooth/BluetoothSocket.cpp
+++ b/dom/bluetooth/BluetoothSocket.cpp
@@ -72,27 +72,27 @@ BluetoothSocket::ReceiveSocketData(nsAut
   mObserver->ReceiveSocketData(this, aMessage);
 }
 
 void
 BluetoothSocket::OnConnectSuccess()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
-  mObserver->OnConnectSuccess(this);
+  mObserver->OnSocketConnectSuccess(this);
 }
 
 void
 BluetoothSocket::OnConnectError()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
-  mObserver->OnConnectError(this);
+  mObserver->OnSocketConnectError(this);
 }
 
 void
 BluetoothSocket::OnDisconnect()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
-  mObserver->OnDisconnect(this);
+  mObserver->OnSocketDisconnect(this);
 }
 
--- a/dom/bluetooth/BluetoothSocketObserver.h
+++ b/dom/bluetooth/BluetoothSocketObserver.h
@@ -16,34 +16,34 @@ BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSocket;
 
 class BluetoothSocketObserver
 {
 public:
   virtual void ReceiveSocketData(BluetoothSocket* aSocket,
                                  nsAutoPtr<UnixSocketRawData>& aMessage) = 0;
- 
+
    /**
     * A callback function which would be called when a socket connection
     * is established successfully. To be more specific, this would be called
     * when socket state changes from CONNECTING/LISTENING to CONNECTED.
     */
-  virtual void OnConnectSuccess(BluetoothSocket* aSocket) = 0;
- 
+  virtual void OnSocketConnectSuccess(BluetoothSocket* aSocket) = 0;
+
    /**
     * A callback function which would be called when BluetoothSocket::Connect()
     * fails.
     */
-  virtual void OnConnectError(BluetoothSocket* aSocket) = 0;
- 
+  virtual void OnSocketConnectError(BluetoothSocket* aSocket) = 0;
+
    /**
     * A callback function which would be called when a socket connection
     * is dropped. To be more specific, this would be called when socket state
     * changes from CONNECTED/LISTENING to DISCONNECTED.
     */
-  virtual void OnDisconnect(BluetoothSocket* aSocket) = 0;
+  virtual void OnSocketDisconnect(BluetoothSocket* aSocket) = 0;
 
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothUuid.cpp
+++ b/dom/bluetooth/BluetoothUuid.cpp
@@ -32,20 +32,27 @@ BluetoothUuidHelper::GetBluetoothService
    */
   BluetoothServiceClass retValue = BluetoothServiceClass::UNKNOWN;
   nsString uuid(Substring(aUuidStr, 4, 4));
 
   nsresult rv;
   int32_t integer = uuid.ToInteger(&rv, 16);
   NS_ENSURE_SUCCESS(rv, retValue);
 
-  switch (integer) {
+  return GetBluetoothServiceClass(integer);
+}
+
+BluetoothServiceClass
+BluetoothUuidHelper::GetBluetoothServiceClass(uint16_t aProfileId)
+{
+  BluetoothServiceClass retValue = BluetoothServiceClass::UNKNOWN;
+  switch (aProfileId) {
     case BluetoothServiceClass::A2DP:
     case BluetoothServiceClass::HANDSFREE:
     case BluetoothServiceClass::HANDSFREE_AG:
     case BluetoothServiceClass::HEADSET:
     case BluetoothServiceClass::HEADSET_AG:
     case BluetoothServiceClass::HID:
     case BluetoothServiceClass::OBJECT_PUSH:
-      retValue = (BluetoothServiceClass)integer;
+      retValue = (BluetoothServiceClass)aProfileId;
   }
   return retValue;
 }
--- a/dom/bluetooth/BluetoothUuid.h
+++ b/dom/bluetooth/BluetoothUuid.h
@@ -48,16 +48,19 @@ public:
   /**
    * Convert a 128-bit uuid string to a value of BluetoothServiceClass
    *
    * @param aUuidStr  128-bit uuid string
    * @return  a value of BluetoothServiceClass
    */
   static BluetoothServiceClass
   GetBluetoothServiceClass(const nsAString& aUuidStr);
+
+  static BluetoothServiceClass
+  GetBluetoothServiceClass(uint16_t aProfileId);
 };
 
 // TODO/qdot: Move these back into gonk and make the service handler deal with
 // it there.
 //
 // Gotten from reading the "u8" values in B2G/external/bluez/src/adapter.c
 // These were hardcoded into android
 enum BluetoothReservedChannels {
--- a/dom/bluetooth/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -383,23 +383,24 @@ BluetoothRequestParent::DoRequest(const 
   MOZ_ASSERT(mRequestType == Request::TPairedDevicePropertiesRequest);
 
   nsresult rv =
     mService->GetPairedDevicePropertiesInternal(aRequest.addresses(),
                                                 mReplyRunnable.get());
   NS_ENSURE_SUCCESS(rv, false);
   return true;
 }
+
 bool
 BluetoothRequestParent::DoRequest(const ConnectedDevicePropertiesRequest& aRequest)
 {
   MOZ_ASSERT(mService);
   MOZ_ASSERT(mRequestType == Request::TConnectedDevicePropertiesRequest);
   nsresult rv =
-    mService->GetConnectedDevicePropertiesInternal(aRequest.profileId(),
+    mService->GetConnectedDevicePropertiesInternal(aRequest.serviceUuid(),
                                                 mReplyRunnable.get());
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
 bool
 BluetoothRequestParent::DoRequest(const SetPinCodeRequest& aRequest)
@@ -469,29 +470,31 @@ BluetoothRequestParent::DoRequest(const 
 
 bool
 BluetoothRequestParent::DoRequest(const ConnectRequest& aRequest)
 {
   MOZ_ASSERT(mService);
   MOZ_ASSERT(mRequestType == Request::TConnectRequest);
 
   mService->Connect(aRequest.address(),
-                    aRequest.profileId(),
+                    aRequest.cod(),
+                    aRequest.serviceUuid(),
                     mReplyRunnable.get());
 
   return true;
 }
 
 bool
 BluetoothRequestParent::DoRequest(const DisconnectRequest& aRequest)
 {
   MOZ_ASSERT(mService);
   MOZ_ASSERT(mRequestType == Request::TDisconnectRequest);
 
-  mService->Disconnect(aRequest.profileId(),
+  mService->Disconnect(aRequest.address(),
+                       aRequest.serviceUuid(),
                        mReplyRunnable.get());
 
   return true;
 }
 
 bool
 BluetoothRequestParent::DoRequest(const SendFileRequest& aRequest)
 {
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -99,20 +99,20 @@ BluetoothServiceChildProcess::GetDefault
                                               BluetoothReplyRunnable* aRunnable)
 {
   SendRequest(aRunnable, DefaultAdapterPathRequest());
   return NS_OK;
 }
 
 nsresult
 BluetoothServiceChildProcess::GetConnectedDevicePropertiesInternal(
-                                              uint16_t aProfileId,
+                                              uint16_t aServiceUuid,
                                               BluetoothReplyRunnable* aRunnable)
 {
-  SendRequest(aRunnable, ConnectedDevicePropertiesRequest(aProfileId));
+  SendRequest(aRunnable, ConnectedDevicePropertiesRequest(aServiceUuid));
   return NS_OK;
 }
 nsresult
 BluetoothServiceChildProcess::GetPairedDevicePropertiesInternal(
                                      const nsTArray<nsString>& aDeviceAddresses,
                                      BluetoothReplyRunnable* aRunnable)
 {
   PairedDevicePropertiesRequest request;
@@ -248,30 +248,34 @@ BluetoothServiceChildProcess::SetPairing
                 DenyPairingConfirmationRequest(nsString(aDeviceAddress)));
   }
   return true;
 }
 
 void
 BluetoothServiceChildProcess::Connect(
   const nsAString& aDeviceAddress,
-  const uint16_t aProfileId,
+  uint32_t aCod,
+  uint16_t aServiceUuid,
   BluetoothReplyRunnable* aRunnable)
 {
   SendRequest(aRunnable,
               ConnectRequest(nsString(aDeviceAddress),
-                             aProfileId));
+                             aCod,
+                             aServiceUuid));
 }
 
 void
 BluetoothServiceChildProcess::Disconnect(
-  const uint16_t aProfileId,
+  const nsAString& aDeviceAddress,
+  uint16_t aServiceUuid,
   BluetoothReplyRunnable* aRunnable)
 {
-  SendRequest(aRunnable, DisconnectRequest(aProfileId));
+  SendRequest(aRunnable,
+              DisconnectRequest(nsString(aDeviceAddress), aServiceUuid));
 }
 
 void
 BluetoothServiceChildProcess::SendFile(
   const nsAString& aDeviceAddress,
   BlobParent* aBlobParent,
   BlobChild* aBlobChild,
   BluetoothReplyRunnable* aRunnable)
@@ -382,17 +386,17 @@ BluetoothServiceChildProcess::StopIntern
 
 bool
 BluetoothServiceChildProcess::IsEnabledInternal()
 {
   MOZ_CRASH("This should never be called!");
 }
 
 bool
-BluetoothServiceChildProcess::IsConnected(uint16_t aProfileId)
+BluetoothServiceChildProcess::IsConnected(uint16_t aServiceUuid)
 {
   MOZ_CRASH("This should never be called!");
 }
 
 nsresult
 BluetoothServiceChildProcess::SendSinkMessage(const nsAString& aDeviceAddresses,
                                               const nsAString& aMessage)
 {
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
@@ -47,17 +47,17 @@ public:
   GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
   GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
                                     BluetoothReplyRunnable* aRunnable)
                                     MOZ_OVERRIDE;
 
   virtual nsresult
-  GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
+  GetConnectedDevicePropertiesInternal(uint16_t aServiceUuid,
                                        BluetoothReplyRunnable* aRunnable)
                                        MOZ_OVERRIDE;
   virtual nsresult
   StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
   StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
@@ -108,25 +108,27 @@ public:
   virtual bool
   SetPairingConfirmationInternal(const nsAString& aDeviceAddress,
                                  bool aConfirm,
                                  BluetoothReplyRunnable* aRunnable)
                                  MOZ_OVERRIDE;
 
   virtual void
   Connect(const nsAString& aDeviceAddress,
-          const uint16_t aProfileId,
+          uint32_t aCod,
+          uint16_t aServiceUuid,
           BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
-  Disconnect(const uint16_t aProfileId,
+  Disconnect(const nsAString& aDeviceAddress,
+             uint16_t aServiceUuid,
              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual bool
-  IsConnected(uint16_t aProfileId) MOZ_OVERRIDE;
+  IsConnected(uint16_t aServiceUuid) MOZ_OVERRIDE;
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
--- a/dom/bluetooth/ipc/PBluetooth.ipdl
+++ b/dom/bluetooth/ipc/PBluetooth.ipdl
@@ -77,30 +77,33 @@ struct DenyPairingConfirmationRequest
 {
   nsString path;
 };
 
 struct PairedDevicePropertiesRequest
 {
   nsString[] addresses;
 };
+
 struct ConnectedDevicePropertiesRequest
 {
-  uint16_t profileId;
+  uint16_t serviceUuid;
 };
 
 struct ConnectRequest
 {
   nsString address;
-  uint16_t profileId;
+  uint32_t cod;
+  uint16_t serviceUuid;
 };
 
 struct DisconnectRequest
 {
-  uint16_t profileId;
+  nsString address;
+  uint16_t serviceUuid;
 };
 
 struct SendFileRequest
 {
   nsString devicePath;
   PBlob blob;
 };
 
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -17,16 +17,17 @@
 */
 
 #include "base/basictypes.h"
 #include "BluetoothDBusService.h"
 #include "BluetoothA2dpManager.h"
 #include "BluetoothHfpManager.h"
 #include "BluetoothHidManager.h"
 #include "BluetoothOppManager.h"
+#include "BluetoothProfileController.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUnixSocketConnector.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 
 #include <cstdio>
 #include <dbus/dbus.h>
 
@@ -174,16 +175,17 @@ static const char* sBluetoothDBusSignals
  */
 static nsRefPtr<RawDBusConnection> gThreadConnection;
 static nsDataHashtable<nsStringHashKey, DBusMessage* >* sPairingReqTable;
 static nsTArray<uint32_t> sAuthorizedServiceClass;
 static nsString sAdapterPath;
 static Atomic<int32_t> sIsPairing(0);
 static int sConnectedDeviceCount = 0;
 static StaticAutoPtr<Monitor> sStopBluetoothMonitor;
+StaticAutoPtr<BluetoothProfileController> sController;
 
 typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
 typedef bool (*FilterFunc)(const BluetoothValue&);
 
 BluetoothDBusService::BluetoothDBusService()
 {
   sStopBluetoothMonitor = new Monitor("BluetoothService.sStopBluetoothMonitor");
 }
@@ -2161,37 +2163,37 @@ private:
   const nsTArray<nsString> mDeviceAddresses;
   nsTArray<nsString>::size_type mProcessedDeviceAddresses;
   const FilterFunc mFilterFunc;
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
   BluetoothValue mValues;
 };
 
 nsresult
-BluetoothDBusService::GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
+BluetoothDBusService::GetConnectedDevicePropertiesInternal(uint16_t aServiceUuid,
                                               BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoString errorStr;
   BluetoothValue values = InfallibleTArray<BluetoothNamedValue>();
   if (!IsReady()) {
     NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
     DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
     return NS_OK;
   }
 
   nsTArray<nsString> deviceAddresses;
   BluetoothProfileManagerBase* profile;
-  if (aProfileId == BluetoothServiceClass::HANDSFREE ||
-      aProfileId == BluetoothServiceClass::HEADSET) {
+  if (aServiceUuid == BluetoothServiceClass::HANDSFREE ||
+      aServiceUuid == BluetoothServiceClass::HEADSET) {
     profile = BluetoothHfpManager::Get();
-  } else if (aProfileId == BluetoothServiceClass::HID) {
+  } else if (aServiceUuid == BluetoothServiceClass::HID) {
     profile = BluetoothHidManager::Get();
-  } else if (aProfileId == BluetoothServiceClass::OBJECT_PUSH) {
+  } else if (aServiceUuid == BluetoothServiceClass::OBJECT_PUSH) {
     profile = BluetoothOppManager::Get();
   } else {
     DispatchBluetoothReply(aRunnable, values,
                            NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
     return NS_OK;
   }
 
   if (profile->IsConnected()) {
@@ -2584,80 +2586,89 @@ BluetoothDBusService::SetPairingConfirma
   dbus_message_unref(msg);
   dbus_message_unref(reply);
 
   sPairingReqTable->Remove(aDeviceAddress);
   DispatchBluetoothReply(aRunnable, v, errorStr);
   return result;
 }
 
+static void
+DestroyBluetoothProfileController()
+{
+  sController = nullptr;
+}
+
 void
 BluetoothDBusService::Connect(const nsAString& aDeviceAddress,
-                              const uint16_t aProfileId,
+                              uint32_t aCod,
+                              uint16_t aServiceUuid,
                               BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
-
-  if (aProfileId == BluetoothServiceClass::HANDSFREE) {
-    BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
-    hfp->Connect(aDeviceAddress, true, aRunnable);
-  } else if (aProfileId == BluetoothServiceClass::HEADSET) {
-    BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
-    hfp->Connect(aDeviceAddress, false, aRunnable);
-  } else if (aProfileId == BluetoothServiceClass::HID) {
-    BluetoothHidManager* hid = BluetoothHidManager::Get();
-    hid->Connect(aDeviceAddress, aRunnable);
-  } else if (aProfileId == BluetoothServiceClass::OBJECT_PUSH) {
-    BluetoothOppManager* opp = BluetoothOppManager::Get();
-    opp->Connect(aDeviceAddress, aRunnable);
+  MOZ_ASSERT(aRunnable);
+
+  BluetoothServiceClass serviceClass =
+    BluetoothUuidHelper::GetBluetoothServiceClass(aServiceUuid);
+
+  if (sController) {
+    DispatchBluetoothReply(aRunnable, BluetoothValue(),
+                           NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
+    return;
+  }
+
+  sController =
+    new BluetoothProfileController(aDeviceAddress, aRunnable,
+                                   DestroyBluetoothProfileController);
+  if (aServiceUuid) {
+    sController->Connect(serviceClass);
   } else {
-    DispatchBluetoothReply(aRunnable, BluetoothValue(),
-                           NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
+    sController->Connect(aCod);
   }
 }
 
 void
-BluetoothDBusService::Disconnect(const uint16_t aProfileId,
+BluetoothDBusService::Disconnect(const nsAString& aDeviceAddress,
+                                 uint16_t aServiceUuid,
                                  BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
-
-  if (aProfileId == BluetoothServiceClass::HANDSFREE ||
-      aProfileId == BluetoothServiceClass::HEADSET) {
-    BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
-    hfp->Disconnect();
-  } else if (aProfileId == BluetoothServiceClass::HID) {
-    BluetoothHidManager* hid = BluetoothHidManager::Get();
-    hid->Disconnect();
-  } else if (aProfileId == BluetoothServiceClass::OBJECT_PUSH) {
-    BluetoothOppManager* opp = BluetoothOppManager::Get();
-    opp->Disconnect();
-  } else {
-    BT_WARNING(ERR_UNKNOWN_PROFILE);
+  MOZ_ASSERT(aRunnable);
+
+  BluetoothServiceClass serviceClass =
+    BluetoothUuidHelper::GetBluetoothServiceClass(aServiceUuid);
+
+  if (sController) {
+    DispatchBluetoothReply(aRunnable, BluetoothValue(),
+                           NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
     return;
   }
 
-  // Currently, just fire success because Disconnect() doesn't fail,
-  // but we still make aRunnable pass into this function for future
-  // once Disconnect will fail.
-  DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
+  sController =
+    new BluetoothProfileController(aDeviceAddress, aRunnable,
+                                   DestroyBluetoothProfileController);
+  if (aServiceUuid) {
+    sController->Disconnect(serviceClass);
+  } else {
+    sController->Disconnect();
+  }
 }
 
 bool
-BluetoothDBusService::IsConnected(const uint16_t aProfileId)
+BluetoothDBusService::IsConnected(const uint16_t aServiceUuid)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothProfileManagerBase* profile;
-  if (aProfileId == BluetoothServiceClass::HANDSFREE ||
-      aProfileId == BluetoothServiceClass::HEADSET) {
+  if (aServiceUuid == BluetoothServiceClass::HANDSFREE ||
+      aServiceUuid == BluetoothServiceClass::HEADSET) {
     profile = BluetoothHfpManager::Get();
-  } else if (aProfileId == BluetoothServiceClass::HID) {
+  } else if (aServiceUuid == BluetoothServiceClass::HID) {
     profile = BluetoothHidManager::Get();
-  } else if (aProfileId == BluetoothServiceClass::OBJECT_PUSH) {
+  } else if (aServiceUuid == BluetoothServiceClass::OBJECT_PUSH) {
     profile = BluetoothOppManager::Get();
   } else {
     NS_WARNING(ERR_UNKNOWN_PROFILE);
     return false;
   }
 
   NS_ENSURE_TRUE(profile, false);
   return profile->IsConnected();
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -31,17 +31,17 @@ public:
 
   virtual nsresult StopInternal() MOZ_OVERRIDE;
 
   virtual bool IsEnabledInternal() MOZ_OVERRIDE;
 
   virtual nsresult GetDefaultAdapterPathInternal(
                                              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
-  virtual nsresult GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
+  virtual nsresult GetConnectedDevicePropertiesInternal(uint16_t aServiceUuid,
                                              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult GetPairedDevicePropertiesInternal(
                                      const nsTArray<nsString>& aDeviceAddresses,
                                      BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
@@ -97,24 +97,26 @@ public:
                      BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual bool
   SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm,
                                  BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   Connect(const nsAString& aDeviceAddress,
-          const uint16_t aProfileId,
-          BluetoothReplyRunnable* aRunnable);
+          uint32_t aCod,
+          uint16_t aServiceUuid,
+          BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual bool
-  IsConnected(uint16_t aProfileId) MOZ_OVERRIDE;
+  IsConnected(uint16_t aServiceUuid) MOZ_OVERRIDE;
 
   virtual void
-  Disconnect(const uint16_t aProfileId, BluetoothReplyRunnable* aRunnable);
+  Disconnect(const nsAString& aDeviceAddress, uint16_t aServiceUuid,
+             BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -39,16 +39,17 @@ if CONFIG['MOZ_B2G_BT']:
         'BluetoothUnixSocketConnector.cpp',
         'BluetoothA2dpManager.cpp',
         'BluetoothHfpManager.cpp',
         'BluetoothHidManager.cpp',
         'BluetoothOppManager.cpp',
         'ObexBase.cpp',
         'BluetoothUuid.cpp',
         'BluetoothSocket.cpp',
+        'BluetoothProfileController.cpp'
     ]
 
     if CONFIG['MOZ_B2G_RIL']:
         CPP_SOURCES += [
             'BluetoothTelephonyListener.cpp',
         ]
 
     if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
--- a/dom/webidl/BluetoothAdapter.webidl
+++ b/dom/webidl/BluetoothAdapter.webidl
@@ -83,36 +83,42 @@ interface BluetoothAdapter : EventTarget
   DOMRequest stopDiscovery();
   [Creator, Throws]
   DOMRequest pair(BluetoothDevice device);
   [Creator, Throws]
   DOMRequest unpair(BluetoothDevice device);
   [Creator, Throws]
   DOMRequest getPairedDevices();
   [Creator, Throws]
-  DOMRequest getConnectedDevices(unsigned short profile);
+  DOMRequest getConnectedDevices(unsigned short serviceUuid);
   [Creator, Throws]
   DOMRequest setPinCode(DOMString deviceAddress, DOMString pinCode);
   [Creator, Throws]
   DOMRequest setPasskey(DOMString deviceAddress, unsigned long passkey);
   [Creator, Throws]
   DOMRequest setPairingConfirmation(DOMString deviceAddress, boolean confirmation);
 
   /**
    * Connect/Disconnect to a specific service of a target remote device.
    * To check the value of service UUIDs, please check "Bluetooth Assigned
    * Numbers" / "Service Discovery Protocol" for more information.
    *
-   * @param deviceAddress Remote device address
-   * @param profile 2-octets service UUID
+   * Note that service UUID is optional. If it isn't passed when calling
+   * Connect, multiple profiles are tried sequentially based on the class of
+   * device (CoD). If it isn't passed when calling Disconnect, all connected
+   * profiles are going to be closed.
+   *
+   * @param device Remote device
+   * @param profile 2-octets service UUID. This is optional.
    */
   [Creator, Throws]
-  DOMRequest connect(DOMString deviceAddress, unsigned short profile);
+  DOMRequest connect(BluetoothDevice device, optional unsigned short serviceUuid);
+
   [Creator, Throws]
-  DOMRequest disconnect(unsigned short profile);
+  DOMRequest disconnect(BluetoothDevice device, optional unsigned short serviceUuid);
 
   // One device can only send one file at a time
   [Creator, Throws]
   DOMRequest sendFile(DOMString deviceAddress, Blob blob);
   [Creator, Throws]
   DOMRequest stopSendingFile(DOMString deviceAddress);
   [Creator, Throws]
   DOMRequest confirmReceivingFile(DOMString deviceAddress, boolean confirmation);