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 159705 ef9b729c38a1253accb6baa87f402046994bb40c
parent 159704 ffd9e8e157dd50d3aec572adc8a2be658d56da9a
child 159706 585da14f78e27c3f9b7180d6c5c651b074eb786e
push idunknown
push userunknown
push dateunknown
reviewersechou, mrbkap
bugs906305
milestone26.0a1
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);