diff --git a/dom/bluetooth2/bluedroid/BluetoothInterface.cpp b/dom/bluetooth2/bluedroid/BluetoothInterface.cpp index 5fd4e73742ad..8b366d973d0d 100644 --- a/dom/bluetooth2/bluedroid/BluetoothInterface.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothInterface.cpp @@ -617,16 +617,29 @@ BluetoothHandsfreeInterface::BluetoothHandsfreeInterface( 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 */ diff --git a/dom/bluetooth2/bluedroid/BluetoothInterface.h b/dom/bluetooth2/bluedroid/BluetoothInterface.h index c67170ed1baf..308c257fd8a3 100644 --- a/dom/bluetooth2/bluedroid/BluetoothInterface.h +++ b/dom/bluetooth2/bluedroid/BluetoothInterface.h @@ -112,8 +112,9 @@ 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 */ diff --git a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp index 855d09b08186..e748d1b1cc91 100644 --- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp +++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp @@ -428,6 +428,72 @@ BluetoothHfpManager::Init() 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 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 mRes; +}; + // static void BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes) @@ -441,11 +507,6 @@ BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes) return; } - if (sBluetoothHfpInterface) { - sBluetoothHfpInterface->Cleanup(); - sBluetoothHfpInterface = nullptr; - } - BluetoothHandsfreeInterface *interface = btInf->GetBluetoothHandsfreeInterface(); if (!interface) { @@ -456,17 +517,19 @@ BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes) return; } - if (interface->Init(&sBluetoothHfpCallbacks) != BT_STATUS_SUCCESS) { - if (aRes) { - aRes->OnError(NS_ERROR_FAILURE); + nsRefPtr res = + new CleanupInitResultHandler(interface, aRes); + + 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 r = new InitResultHandlerRunnable(res); + if (NS_FAILED(NS_DispatchToMainThread(r))) { + BT_LOGR("Failed to dispatch HFP init runnable"); } - return; - } - - sBluetoothHfpInterface = interface; - - if (aRes) { - aRes->Init(); } } @@ -488,16 +551,65 @@ BluetoothHfpManager::~BluetoothHfpManager() 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 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 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 r = new DeinitResultHandlerRunnable(aRes); + if (NS_FAILED(NS_DispatchToMainThread(r))) { + BT_LOGR("Failed to dispatch cleanup-result-handler runnable"); + } } }