Bug 913372 - Patch 1: Refine the architecture of BluetoothProfileController, r=echou

This commit is contained in:
Gina Yeh 2013-10-28 12:06:38 +08:00
parent bc82b3c087
commit daf93ad679
2 changed files with 136 additions and 106 deletions

View File

@ -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();
}

View File

@ -53,47 +53,76 @@ 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);
/**
* 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<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