Bug 1029389: Asynchronous Bluetooth Handsfree init and cleanup methods, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Tue, 15 Jul 2014 10:56:53 +0200
changeset 216018 fb5dc920ee5afe5579deb16c4108d25c2dffc82d
parent 216017 33418069c4e2a995b2d5c4b17db793a90a1a4273
child 216019 a1a2aa084ce06fcc7b3b851a19ea9134a0f2cc50
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1029389
milestone33.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 1029389: Asynchronous Bluetooth Handsfree init and cleanup methods, r=shuang
dom/bluetooth/bluedroid/BluetoothInterface.cpp
dom/bluetooth/bluedroid/BluetoothInterface.h
dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
--- a/dom/bluetooth/bluedroid/BluetoothInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.cpp
@@ -612,26 +612,39 @@ BluetoothHandsfreeInterface::BluetoothHa
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothHandsfreeInterface::~BluetoothHandsfreeInterface()
 { }
 
-bt_status_t
-BluetoothHandsfreeInterface::Init(bthf_callbacks_t* aCallbacks)
+void
+BluetoothHandsfreeInterface::Init(bthf_callbacks_t* aCallbacks,
+                                  BluetoothHandsfreeResultHandler* aRes)
 {
-  return mInterface->init(aCallbacks);
+  bt_status_t status = mInterface->init(aCallbacks);
+
+  if (aRes) {
+    DispatchBluetoothHandsfreeResult(aRes,
+                                     &BluetoothHandsfreeResultHandler::Init,
+                                     status);
+  }
 }
 
 void
-BluetoothHandsfreeInterface::Cleanup()
+BluetoothHandsfreeInterface::Cleanup(BluetoothHandsfreeResultHandler* aRes)
 {
   mInterface->cleanup();
+
+  if (aRes) {
+    DispatchBluetoothHandsfreeResult(aRes,
+                                     &BluetoothHandsfreeResultHandler::Cleanup,
+                                     BT_STATUS_SUCCESS);
+  }
 }
 
 /* Connect / Disconnect */
 
 bt_status_t
 BluetoothHandsfreeInterface::Connect(bt_bdaddr_t* aBdAddr)
 {
   return mInterface->connect(aBdAddr);
--- a/dom/bluetooth/bluedroid/BluetoothInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.h
@@ -107,18 +107,19 @@ public:
   virtual void PhoneStateChange() { }
 };
 
 class BluetoothHandsfreeInterface
 {
 public:
   friend class BluetoothInterface;
 
-  bt_status_t Init(bthf_callbacks_t* aCallbacks);
-  void        Cleanup();
+  void Init(bthf_callbacks_t* aCallbacks,
+            BluetoothHandsfreeResultHandler* aRes);
+  void Cleanup(BluetoothHandsfreeResultHandler* aRes);
 
   /* Connect / Disconnect */
 
   bt_status_t Connect(bt_bdaddr_t* aBdAddr);
   bt_status_t Disconnect(bt_bdaddr_t* aBdAddr);
   bt_status_t ConnectAudio(bt_bdaddr_t* aBdAddr);
   bt_status_t DisconnectAudio(bt_bdaddr_t* aBdAddr);
 
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -429,41 +429,106 @@ BluetoothHfpManager::Init()
 
   nsRefPtr<GetVolumeTask> callback = new GetVolumeTask();
   rv = settingsLock->Get(AUDIO_VOLUME_BT_SCO_ID, callback);
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
+class CleanupInitResultHandler MOZ_FINAL : public BluetoothHandsfreeResultHandler
+{
+public:
+  CleanupInitResultHandler(BluetoothHandsfreeInterface* aInterface,
+                           BluetoothProfileResultHandler* aRes)
+  : mInterface(aInterface)
+  , mRes(aRes)
+  {
+    MOZ_ASSERT(mInterface);
+  }
+
+  void OnError(bt_status_t aStatus) MOZ_OVERRIDE
+  {
+    BT_WARNING("BluetoothHandsfreeInterface::Init failed: %d", (int)aStatus);
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void Init() MOZ_OVERRIDE
+  {
+    sBluetoothHfpInterface = mInterface;
+    if (mRes) {
+      mRes->Init();
+    }
+  }
+
+  void Cleanup() MOZ_OVERRIDE
+  {
+    sBluetoothHfpInterface = nullptr;
+    /* During re-initialization, a previouly initialized
+     * |BluetoothHandsfreeInterface| has now been cleaned
+     * up, so we start initialization.
+     */
+    RunInit();
+  }
+
+  void RunInit()
+  {
+    mInterface->Init(&sBluetoothHfpCallbacks, this);
+  }
+
+private:
+  BluetoothHandsfreeInterface* mInterface;
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+
+class InitResultHandlerRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  InitResultHandlerRunnable(CleanupInitResultHandler* aRes)
+  : mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE
+  {
+    mRes->RunInit();
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<CleanupInitResultHandler> mRes;
+};
+
 // static
 void
 BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
 {
   BluetoothInterface* btInf = BluetoothInterface::GetInstance();
   NS_ENSURE_TRUE_VOID(btInf);
 
-  if (sBluetoothHfpInterface) {
-    sBluetoothHfpInterface->Cleanup();
-    sBluetoothHfpInterface = nullptr;
-  }
-
   BluetoothHandsfreeInterface *interface =
     btInf->GetBluetoothHandsfreeInterface();
   NS_ENSURE_TRUE_VOID(interface);
 
-  if (interface->Init(&sBluetoothHfpCallbacks) != BT_STATUS_SUCCESS) {
-    aRes->OnError(NS_ERROR_FAILURE);
-    return;
-  }
+  nsRefPtr<CleanupInitResultHandler> res =
+    new CleanupInitResultHandler(interface, aRes);
 
-  sBluetoothHfpInterface = interface;
-
-  if (aRes) {
-    aRes->Init();
+  if (sBluetoothHfpInterface) {
+    // Cleanup an initialized HFP before initializing again.
+    sBluetoothHfpInterface->Cleanup(res);
+  } else {
+    // If there's no HFP interface to cleanup first, we dispatch
+    // a runnable that calls the profile result handler.
+    nsRefPtr<nsRunnable> r = new InitResultHandlerRunnable(res);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP init runnable");
+    }
   }
 }
 
 BluetoothHfpManager::~BluetoothHfpManager()
 {
   if (!mListener->Listen(false)) {
     BT_WARNING("Failed to stop listening RIL");
   }
@@ -475,26 +540,75 @@ BluetoothHfpManager::~BluetoothHfpManage
   if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
       NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID))) {
     BT_WARNING("Failed to remove observers!");
   }
 
   hal::UnregisterBatteryObserver(this);
 }
 
+class CleanupResultHandler MOZ_FINAL : public BluetoothHandsfreeResultHandler
+{
+public:
+  CleanupResultHandler(BluetoothProfileResultHandler* aRes)
+  : mRes(aRes)
+  { }
+
+  void OnError(bt_status_t aStatus) MOZ_OVERRIDE
+  {
+    BT_WARNING("BluetoothHandsfreeInterface::Cleanup failed: %d", (int)aStatus);
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void Cleanup() MOZ_OVERRIDE
+  {
+    sBluetoothHfpInterface = nullptr;
+    if (mRes) {
+      mRes->Deinit();
+    }
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+
+class DeinitResultHandlerRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  DeinitResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
+  : mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE
+  {
+    mRes->Deinit();
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+
 // static
 void
 BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
 {
   if (sBluetoothHfpInterface) {
-    sBluetoothHfpInterface->Cleanup();
-    sBluetoothHfpInterface = nullptr;
-  }
-  if (aRes) {
-    aRes->Deinit();
+    sBluetoothHfpInterface->Cleanup(new CleanupResultHandler(aRes));
+  } else if (aRes) {
+    // We dispatch a runnable here to make the profile resource handler
+    // behave as if HFP was initialized.
+    nsRefPtr<nsRunnable> r = new DeinitResultHandlerRunnable(aRes);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
+    }
   }
 }
 
 //static
 BluetoothHfpManager*
 BluetoothHfpManager::Get()
 {
   MOZ_ASSERT(NS_IsMainThread());