Bug 913372 - Patch 1: Refine the architecture of BluetoothProfileController, r=echou
authorGina Yeh <gyeh@mozilla.com>
Mon, 28 Oct 2013 12:06:38 +0800
changeset 167220 a11f3d159ce7ea488b8ba608249e083f8307c823
parent 167219 80734c181020ddd859cbdfbd89034595d96c7ad4
child 167221 af4f7b0cebe4a0bd5d5082ad74cb3c1d15451226
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechou
bugs913372
milestone27.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 913372 - Patch 1: Refine the architecture of BluetoothProfileController, r=echou
dom/bluetooth/BluetoothProfileController.cpp
dom/bluetooth/BluetoothProfileController.h
--- a/dom/bluetooth/BluetoothProfileController.cpp
+++ b/dom/bluetooth/BluetoothProfileController.cpp
@@ -21,40 +21,58 @@ USING_BLUETOOTH_NAMESPACE
   do {                                                \
     nsCString name;                                   \
     mgr->GetName(name);                               \
     BT_LOGR("%s: [%s] %s", __FUNCTION__, name.get(),  \
       nsPrintfCString(args).get());                   \
   } while(0)
 
 BluetoothProfileController::BluetoothProfileController(
+                                   bool aConnect,
                                    const nsAString& aDeviceAddress,
                                    BluetoothReplyRunnable* aRunnable,
-                                   BluetoothProfileControllerCallback aCallback)
-  : mCallback(aCallback)
+                                   BluetoothProfileControllerCallback aCallback,
+                                   uint16_t aServiceUuid,
+                                   uint32_t aCod)
+  : mConnect(aConnect)
   , mDeviceAddress(aDeviceAddress)
   , mRunnable(aRunnable)
+  , mCallback(aCallback)
   , mSuccess(false)
+  , mProfilesIndex(-1)
 {
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
   MOZ_ASSERT(aRunnable);
   MOZ_ASSERT(aCallback);
 
-  mProfilesIndex = -1;
   mProfiles.Clear();
+
+  /**
+   * If the service uuid is not specified, either connect multiple profiles
+   * based on Cod, or disconnect all connected profiles.
+   */
+  if (!aServiceUuid) {
+    mTarget.cod = aCod;
+    SetupProfiles(false);
+  } else {
+    BluetoothServiceClass serviceClass =
+      BluetoothUuidHelper::GetBluetoothServiceClass(aServiceUuid);
+    mTarget.service = serviceClass;
+    SetupProfiles(true);
+  }
 }
 
 BluetoothProfileController::~BluetoothProfileController()
 {
   mProfiles.Clear();
   mRunnable = nullptr;
   mCallback = nullptr;
 }
 
-bool
+void
 BluetoothProfileController::AddProfileWithServiceClass(
                                                    BluetoothServiceClass aClass)
 {
   BluetoothProfileManagerBase* profile;
   switch (aClass) {
     case BluetoothServiceClass::HANDSFREE:
     case BluetoothServiceClass::HEADSET:
       profile = BluetoothHfpManager::Get();
@@ -67,67 +85,76 @@ BluetoothProfileController::AddProfileWi
       break;
     case BluetoothServiceClass::HID:
       profile = BluetoothHidManager::Get();
       break;
     default:
       DispatchBluetoothReply(mRunnable, BluetoothValue(),
                              NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
       mCallback();
-      return false;
+      return;
   }
 
-  return AddProfile(profile);
+  AddProfile(profile);
 }
 
-bool
+void
 BluetoothProfileController::AddProfile(BluetoothProfileManagerBase* aProfile,
                                        bool aCheckConnected)
 {
   if (!aProfile) {
     DispatchBluetoothReply(mRunnable, BluetoothValue(),
                            NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
     mCallback();
-    return false;
+    return;
   }
 
   if (aCheckConnected && !aProfile->IsConnected()) {
-    return false;
+    BT_WARNING("The profile is not connected.");
+    return;
   }
 
   mProfiles.AppendElement(aProfile);
-  return true;
 }
 
 void
-BluetoothProfileController::Connect(BluetoothServiceClass aClass)
+BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  NS_ENSURE_TRUE_VOID(AddProfileWithServiceClass(aClass));
-
-  ConnectNext();
-}
+  /**
+   * When a service class is assigned, only its corresponding profile is put
+   * into array.
+   */
+  if (aAssignServiceClass) {
+    AddProfileWithServiceClass(mTarget.service);
+    return;
+  }
 
-void
-BluetoothProfileController::Connect(uint32_t aCod)
-{
-  MOZ_ASSERT(NS_IsMainThread());
+  // For a disconnect request, all connected profiles are put into array.
+  if (!mConnect) {
+    AddProfile(BluetoothHidManager::Get(), true);
+    AddProfile(BluetoothOppManager::Get(), true);
+    AddProfile(BluetoothA2dpManager::Get(), true);
+    AddProfile(BluetoothHfpManager::Get(), true);
+    return;
+  }
 
-  // Put multiple profiles into array and connect to all of them sequencely
-  bool hasAudio = HAS_AUDIO(aCod);
-  bool hasObjectTransfer = HAS_OBJECT_TRANSFER(aCod);
-  bool hasRendering = HAS_RENDERING(aCod);
-  bool isPeripheral = IS_PERIPHERAL(aCod);
+  /**
+   * For a connect request, put multiple profiles into array and connect to
+   * all of them sequencely.
+   */
+  bool hasAudio = HAS_AUDIO(mTarget.cod);
+  bool hasObjectTransfer = HAS_OBJECT_TRANSFER(mTarget.cod);
+  bool hasRendering = HAS_RENDERING(mTarget.cod);
+  bool isPeripheral = IS_PERIPHERAL(mTarget.cod);
 
   NS_ENSURE_TRUE_VOID(hasAudio || hasObjectTransfer ||
                       hasRendering || isPeripheral);
 
-  mCod = aCod;
-
   /**
    * Connect to HFP/HSP first. Then, connect A2DP if Rendering bit is set.
    * It's almost impossible to send file to a remote device which is an Audio
    * device or a Rendering device, so we won't connect OPP in that case.
    */
   if (hasAudio) {
     AddProfile(BluetoothHfpManager::Get());
   }
@@ -135,30 +162,50 @@ BluetoothProfileController::Connect(uint
     AddProfile(BluetoothA2dpManager::Get());
   }
   if (hasObjectTransfer && !hasAudio && !hasRendering) {
     AddProfile(BluetoothOppManager::Get());
   }
   if (isPeripheral) {
     AddProfile(BluetoothHidManager::Get());
   }
-
-  ConnectNext();
 }
 
 void
-BluetoothProfileController::ConnectNext()
+BluetoothProfileController::Start()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mDeviceAddress.IsEmpty());
+  MOZ_ASSERT(mProfilesIndex == -1);
+
+  ++mProfilesIndex;
+  BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
+
+  if (mConnect) {
+    mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
+  } else {
+    mProfiles[mProfilesIndex]->Disconnect(this);
+  }
+}
+
+void
+BluetoothProfileController::Next()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mDeviceAddress.IsEmpty());
+  MOZ_ASSERT(mProfilesIndex < mProfiles.Length());
 
   if (++mProfilesIndex < mProfiles.Length()) {
-    MOZ_ASSERT(!mDeviceAddress.IsEmpty());
     BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
 
-    mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
+    if (mConnect) {
+      mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
+    } else {
+      mProfiles[mProfilesIndex]->Disconnect(this);
+    }
     return;
   }
 
   MOZ_ASSERT(mRunnable && mCallback);
 
   // The action has been completed, so the dom request is replied and then
   // the callback is invoked
   if (mSuccess) {
@@ -178,72 +225,26 @@ BluetoothProfileController::OnConnect(co
     NS_ConvertUTF16toUTF8(aErrorStr).get());
 
   if (!aErrorStr.IsEmpty()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
   } else {
     mSuccess = true;
   }
 
-  ConnectNext();
-}
-
-void
-BluetoothProfileController::Disconnect(BluetoothServiceClass aClass)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (aClass != BluetoothServiceClass::UNKNOWN) {
-    NS_ENSURE_TRUE_VOID(AddProfileWithServiceClass(aClass));
-
-    DisconnectNext();
-    return;
-  }
-
-  // Put all connected profiles into array and disconnect all of them
-  AddProfile(BluetoothHidManager::Get(), true);
-  AddProfile(BluetoothOppManager::Get(), true);
-  AddProfile(BluetoothA2dpManager::Get(), true);
-  AddProfile(BluetoothHfpManager::Get(), true);
-
-  DisconnectNext();
-}
-
-void
-BluetoothProfileController::DisconnectNext()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (++mProfilesIndex < mProfiles.Length()) {
-    BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
-
-    mProfiles[mProfilesIndex]->Disconnect(this);
-    return;
-  }
-
-  MOZ_ASSERT(mRunnable && mCallback);
-
-  // The action has been completed, so the dom request is replied and then
-  // the callback is invoked
-  if (mSuccess) {
-    DispatchBluetoothReply(mRunnable, BluetoothValue(true), EmptyString());
-  } else {
-    DispatchBluetoothReply(mRunnable, BluetoothValue(),
-                           NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
-  }
-  mCallback();
+  Next();
 }
 
 void
 BluetoothProfileController::OnDisconnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
   BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "<%s>",
     NS_ConvertUTF16toUTF8(aErrorStr).get());
 
   if (!aErrorStr.IsEmpty()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
   } else {
     mSuccess = true;
   }
 
-  DisconnectNext();
+  Next();
 }
--- a/dom/bluetooth/BluetoothProfileController.h
+++ b/dom/bluetooth/BluetoothProfileController.h
@@ -48,54 +48,83 @@ BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothProfileManagerBase;
 class BluetoothReplyRunnable;
 typedef void (*BluetoothProfileControllerCallback)();
 
 class BluetoothProfileController : public RefCounted<BluetoothProfileController>
 {
 public:
-  BluetoothProfileController(const nsAString& aDeviceAddress,
+  /**
+   * @param aConnect:       If it's a connect request, the value should be set
+   *                        to true. For disconnect request, set it to false.
+   * @param aDeviceAddress: The address of remote device.
+   * @param aRunnable:      Once the controller has done, the runnable will be
+   *                        replied. When all connection/disconnection attemps
+   *                        have failed, an error is fired. In other words,
+   *                        reply a success if any attemp successes.
+   * @param aCallback:      The callback will be invoked after the runnable is
+   *                        replied.
+   * @param aServiceUuid:   Connect/Disconnect to the specified profile. Please
+   *                        see enum BluetoothServiceClass for valid value.
+   * @param aCod:           If aServiceUuid is not assigned, i.e. the value is
+   *                        0, the controller connect multiple profiles based on
+   *                        aCod or disconnect all connected profiles.
+   */
+  BluetoothProfileController(bool aConnect,
+                             const nsAString& aDeviceAddress,
                              BluetoothReplyRunnable* aRunnable,
-                             BluetoothProfileControllerCallback aCallback);
+                             BluetoothProfileControllerCallback aCallback,
+                             uint16_t aServiceUuid,
+                             uint32_t aCod = 0);
   ~BluetoothProfileController();
 
-  // Connect to a specific service UUID.
-  void Connect(BluetoothServiceClass aClass);
-
-  // Based on the CoD, connect to multiple profiles sequencely.
-  void Connect(uint32_t aCod);
+  /**
+   * The controller starts connecting/disconnecting profiles one by one
+   * according to the order in array mProfiles.
+   */
+  void Start();
 
   /**
-   * If aClass is assigned with specific service class, disconnect its
-   * corresponding profile. Otherwise, disconnect all profiles connected to the
-   * remote device.
+   * It is invoked after a profile has tried to establish the connection.
+   * An error string is returned when it fails.
    */
-  void Disconnect(BluetoothServiceClass aClass = BluetoothServiceClass::UNKNOWN);
+  void OnConnect(const nsAString& aErrorStr);
 
-  void OnConnect(const nsAString& aErrorStr);
+  /**
+   * It is invoked after a profile has tried to drop the connection.
+   * An error string is returned when it fails.
+   */
   void OnDisconnect(const nsAString& aErrorStr);
 
-  uint32_t GetCod() const
-  {
-    return mCod;
-  }
+private:
+  // Setup data member mProfiles
+  void SetupProfiles(bool aAssignServiceClass);
+
+  // Add profiles into array with/without checking connection status
+  void AddProfile(BluetoothProfileManagerBase* aProfile,
+                  bool aCheckConnected = false);
 
-private:
-  void ConnectNext();
-  void DisconnectNext();
-  bool AddProfile(BluetoothProfileManagerBase* aProfile,
-                  bool aCheckConnected = false);
-  bool AddProfileWithServiceClass(BluetoothServiceClass aClass);
+  // Add specified profile into array
+  void AddProfileWithServiceClass(BluetoothServiceClass aClass);
+
+  // Connect/Disconnect next profile in the array
+  void Next();
 
+  const bool mConnect;
+  nsString mDeviceAddress;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
+  BluetoothProfileControllerCallback mCallback;
+
+  bool mSuccess;
   int8_t mProfilesIndex;
   nsTArray<BluetoothProfileManagerBase*> mProfiles;
 
-  BluetoothProfileControllerCallback mCallback;
-  uint32_t mCod;
-  nsString mDeviceAddress;
-  nsRefPtr<BluetoothReplyRunnable> mRunnable;
-  bool mSuccess;
+  // Either CoD or BluetoothServiceClass is assigned.
+  union {
+    uint32_t cod;
+    BluetoothServiceClass service;
+  } mTarget;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif