From daf93ad679df557b4f7df404e8edda1a22646e58 Mon Sep 17 00:00:00 2001 From: Gina Yeh Date: Mon, 28 Oct 2013 12:06:38 +0800 Subject: [PATCH] Bug 913372 - Patch 1: Refine the architecture of BluetoothProfileController, r=echou --- dom/bluetooth/BluetoothProfileController.cpp | 159 ++++++++++--------- dom/bluetooth/BluetoothProfileController.h | 83 ++++++---- 2 files changed, 136 insertions(+), 106 deletions(-) diff --git a/dom/bluetooth/BluetoothProfileController.cpp b/dom/bluetooth/BluetoothProfileController.cpp index e6f62196519..aeeebec0657 100644 --- a/dom/bluetooth/BluetoothProfileController.cpp +++ b/dom/bluetooth/BluetoothProfileController.cpp @@ -26,20 +26,38 @@ USING_BLUETOOTH_NAMESPACE } 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() @@ -49,7 +67,7 @@ BluetoothProfileController::~BluetoothProfileController() mCallback = nullptr; } -bool +void BluetoothProfileController::AddProfileWithServiceClass( BluetoothServiceClass aClass) { @@ -72,13 +90,13 @@ BluetoothProfileController::AddProfileWithServiceClass( 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) { @@ -86,43 +104,52 @@ BluetoothProfileController::AddProfile(BluetoothProfileManagerBase* 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)); + /** + * When a service class is assigned, only its corresponding profile is put + * into array. + */ + if (aAssignServiceClass) { + AddProfileWithServiceClass(mTarget.service); + return; + } - ConnectNext(); -} + // 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; + } -void -BluetoothProfileController::Connect(uint32_t aCod) -{ - MOZ_ASSERT(NS_IsMainThread()); - - // 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 @@ -140,20 +167,40 @@ BluetoothProfileController::Connect(uint32_t aCod) 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; } @@ -183,53 +230,7 @@ BluetoothProfileController::OnConnect(const nsAString& aErrorStr) 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 @@ -245,5 +246,5 @@ BluetoothProfileController::OnDisconnect(const nsAString& aErrorStr) mSuccess = true; } - DisconnectNext(); + Next(); } diff --git a/dom/bluetooth/BluetoothProfileController.h b/dom/bluetooth/BluetoothProfileController.h index 747abde5f95..e41387705fe 100644 --- a/dom/bluetooth/BluetoothProfileController.h +++ b/dom/bluetooth/BluetoothProfileController.h @@ -53,47 +53,76 @@ typedef void (*BluetoothProfileControllerCallback)(); class BluetoothProfileController : public RefCounted { 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); + + /** + * 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: - void ConnectNext(); - void DisconnectNext(); - bool AddProfile(BluetoothProfileManagerBase* aProfile, - bool aCheckConnected = false); - bool AddProfileWithServiceClass(BluetoothServiceClass aClass); + // Setup data member mProfiles + void SetupProfiles(bool aAssignServiceClass); + // Add profiles into array with/without checking connection status + void AddProfile(BluetoothProfileManagerBase* aProfile, + bool aCheckConnected = false); + + // Add specified profile into array + void AddProfileWithServiceClass(BluetoothServiceClass aClass); + + // Connect/Disconnect next profile in the array + void Next(); + + const bool mConnect; + nsString mDeviceAddress; + nsRefPtr mRunnable; + BluetoothProfileControllerCallback mCallback; + + bool mSuccess; int8_t mProfilesIndex; nsTArray mProfiles; - BluetoothProfileControllerCallback mCallback; - uint32_t mCod; - nsString mDeviceAddress; - nsRefPtr mRunnable; - bool mSuccess; + // Either CoD or BluetoothServiceClass is assigned. + union { + uint32_t cod; + BluetoothServiceClass service; + } mTarget; }; END_BLUETOOTH_NAMESPACE