Bug 906305 - Patch 4: Fix BluetoothHfpManager, r=echou

This commit is contained in:
Gina Yeh 2013-09-06 19:20:43 +08:00
Родитель 53070ae399
Коммит b49c5f26fd
3 изменённых файлов: 116 добавлений и 77 удалений

Просмотреть файл

@ -8,7 +8,7 @@
#include "BluetoothHfpManager.h" #include "BluetoothHfpManager.h"
#include "BluetoothA2dpManager.h" #include "BluetoothProfileController.h"
#include "BluetoothReplyRunnable.h" #include "BluetoothReplyRunnable.h"
#include "BluetoothService.h" #include "BluetoothService.h"
#include "BluetoothSocket.h" #include "BluetoothSocket.h"
@ -358,6 +358,8 @@ BluetoothHfpManager::Reset()
// Please see Bug 878728 for more information. // Please see Bug 878728 for more information.
mBSIR = false; mBSIR = false;
mController = nullptr;
ResetCallArray(); ResetCallArray();
} }
@ -657,7 +659,7 @@ BluetoothHfpManager::HandleShutdown()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
sInShutdown = true; sInShutdown = true;
Disconnect(); Disconnect(nullptr);
DisconnectSco(); DisconnectSco();
sBluetoothHfpManager = nullptr; sBluetoothHfpManager = nullptr;
} }
@ -1000,43 +1002,38 @@ respond_with_ok:
void void
BluetoothHfpManager::Connect(const nsAString& aDeviceAddress, BluetoothHfpManager::Connect(const nsAString& aDeviceAddress,
const bool aIsHandsfree, BluetoothProfileController* aController)
BluetoothReplyRunnable* aRunnable)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aController && !mController);
BluetoothService* bs = BluetoothService::Get(); BluetoothService* bs = BluetoothService::Get();
if (!bs || sInShutdown) { if (!bs || sInShutdown) {
DispatchBluetoothReply(aRunnable, BluetoothValue(), aController->OnConnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
return; return;
} }
if (mSocket) { if (mSocket) {
if (mDeviceAddress == aDeviceAddress) { if (mDeviceAddress == aDeviceAddress) {
DispatchBluetoothReply(aRunnable, BluetoothValue(), aController->OnConnect(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED));
NS_LITERAL_STRING(ERR_ALREADY_CONNECTED));
} else { } else {
DispatchBluetoothReply(aRunnable, BluetoothValue(), aController->OnConnect(NS_LITERAL_STRING(ERR_REACHED_CONNECTION_LIMIT));
NS_LITERAL_STRING(ERR_REACHED_CONNECTION_LIMIT));
} }
return; return;
} }
mNeedsUpdatingSdpRecords = true; mNeedsUpdatingSdpRecords = true;
mIsHandsfree = aIsHandsfree; mIsHandsfree = !IS_HEADSET(aController->GetCod());
nsString uuid; nsString uuid;
if (aIsHandsfree) { if (mIsHandsfree) {
BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid); BluetoothUuidHelper::GetString(BluetoothServiceClass::HANDSFREE, uuid);
} else { } else {
BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, uuid); BluetoothUuidHelper::GetString(BluetoothServiceClass::HEADSET, uuid);
} }
if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) { if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
DispatchBluetoothReply(aRunnable, BluetoothValue(), aController->OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
return; return;
} }
@ -1051,9 +1048,7 @@ BluetoothHfpManager::Connect(const nsAString& aDeviceAddress,
mHeadsetSocket = nullptr; mHeadsetSocket = nullptr;
} }
MOZ_ASSERT(!mRunnable); mController = aController;
mRunnable = aRunnable;
mSocket = mSocket =
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true); new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
} }
@ -1103,16 +1098,22 @@ BluetoothHfpManager::Listen()
} }
void void
BluetoothHfpManager::Disconnect() BluetoothHfpManager::Disconnect(BluetoothProfileController* aController)
{ {
if (mSocket) { MOZ_ASSERT(NS_IsMainThread());
mSocket->Disconnect();
mSocket = nullptr; if (!mSocket) {
if (aController) {
aController->OnDisconnect(NS_LITERAL_STRING(ERR_ALREADY_DISCONNECTED));
}
return;
} }
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); MOZ_ASSERT(!mController);
NS_ENSURE_TRUE_VOID(a2dp);
a2dp->Disconnect(); mController = aController;
mSocket->Disconnect();
mSocket = nullptr;
} }
bool bool
@ -1450,7 +1451,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
} }
void void
BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket) BluetoothHfpManager::OnSocketConnectSuccess(BluetoothSocket* aSocket)
{ {
MOZ_ASSERT(aSocket); MOZ_ASSERT(aSocket);
@ -1486,15 +1487,6 @@ BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
NS_ENSURE_TRUE_VOID(provider); NS_ENSURE_TRUE_VOID(provider);
provider->EnumerateCalls(mListener->GetListener()); provider->EnumerateCalls(mListener->GetListener());
// For active connection request, we need to reply the DOMRequest
if (mRunnable) {
BluetoothValue v = true;
nsString errorStr;
DispatchBluetoothReply(mRunnable, v, errorStr);
mRunnable = nullptr;
}
mFirstCKPD = true; mFirstCKPD = true;
// Cache device path for NotifySettings() since we can't get socket address // Cache device path for NotifySettings() since we can't get socket address
@ -1505,13 +1497,11 @@ BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
ListenSco(); ListenSco();
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); OnConnect(EmptyString());
NS_ENSURE_TRUE_VOID(a2dp);
a2dp->Connect(mDeviceAddress);
} }
void void
BluetoothHfpManager::OnConnectError(BluetoothSocket* aSocket) BluetoothHfpManager::OnSocketConnectError(BluetoothSocket* aSocket)
{ {
// Failed to create a SCO socket // Failed to create a SCO socket
if (aSocket == mScoSocket) { if (aSocket == mScoSocket) {
@ -1519,25 +1509,14 @@ BluetoothHfpManager::OnConnectError(BluetoothSocket* aSocket)
return; return;
} }
// For active connection request, we need to reply the DOMRequest
if (mRunnable) {
NS_NAMED_LITERAL_STRING(replyError,
"Failed to connect with a bluetooth headset!");
DispatchBluetoothReply(mRunnable, BluetoothValue(), replyError);
mRunnable = nullptr;
}
mSocket = nullptr;
mHandsfreeSocket = nullptr; mHandsfreeSocket = nullptr;
mHeadsetSocket = nullptr; mHeadsetSocket = nullptr;
// If connecting for some reason didn't work, restart listening OnConnect(NS_LITERAL_STRING("SocketConnectionError"));
Listen();
} }
void void
BluetoothHfpManager::OnDisconnect(BluetoothSocket* aSocket) BluetoothHfpManager::OnSocketDisconnect(BluetoothSocket* aSocket)
{ {
MOZ_ASSERT(aSocket); MOZ_ASSERT(aSocket);
@ -1552,12 +1531,12 @@ BluetoothHfpManager::OnDisconnect(BluetoothSocket* aSocket)
return; return;
} }
mSocket = nullptr;
DisconnectSco(); DisconnectSco();
Listen();
NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID)); NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
DispatchConnectionStatusChanged(NS_LITERAL_STRING(HFP_STATUS_CHANGED_ID)); DispatchConnectionStatusChanged(NS_LITERAL_STRING(HFP_STATUS_CHANGED_ID));
OnDisconnect(EmptyString());
Reset(); Reset();
} }
@ -1581,11 +1560,7 @@ BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
// Since we have updated SDP records of the target device, we should // Since we have updated SDP records of the target device, we should
// try to get the channel of target service again. // try to get the channel of target service again.
if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) { if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
DispatchBluetoothReply(mRunnable, BluetoothValue(), OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
mRunnable = nullptr;
mSocket = nullptr;
Listen();
} }
} }
@ -1596,7 +1571,6 @@ BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aDeviceAddress.IsEmpty()); MOZ_ASSERT(!aDeviceAddress.IsEmpty());
MOZ_ASSERT(mRunnable);
BluetoothService* bs = BluetoothService::Get(); BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs); NS_ENSURE_TRUE_VOID(bs);
@ -1608,22 +1582,14 @@ BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
mNeedsUpdatingSdpRecords = false; mNeedsUpdatingSdpRecords = false;
bs->UpdateSdpRecords(aDeviceAddress, this); bs->UpdateSdpRecords(aDeviceAddress, this);
} else { } else {
DispatchBluetoothReply(mRunnable, v, OnConnect(NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
NS_LITERAL_STRING(ERR_SERVICE_CHANNEL_NOT_FOUND));
mRunnable = nullptr;
mSocket = nullptr;
Listen();
} }
return; return;
} }
if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) { if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) {
DispatchBluetoothReply(mRunnable, v, OnConnect(NS_LITERAL_STRING("SocketConnectionError"));
NS_LITERAL_STRING("SocketConnectionError"));
mRunnable = nullptr;
mSocket = nullptr;
Listen();
} }
} }
@ -1773,4 +1739,44 @@ BluetoothHfpManager::IsScoConnected()
return false; return false;
} }
void
BluetoothHfpManager::OnConnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
// When we failed to create a socket, restart listening.
if (!aErrorStr.IsEmpty()) {
mSocket = nullptr;
Listen();
}
/**
* On the one hand, notify the controller that we've done for outbound
* connections. On the other hand, we do nothing for inbound connections.
*/
NS_ENSURE_TRUE_VOID(mController);
mController->OnConnect(aErrorStr);
mController = nullptr;
}
void
BluetoothHfpManager::OnDisconnect(const nsAString& aErrorStr)
{
MOZ_ASSERT(NS_IsMainThread());
// Start listening
mSocket = nullptr;
Listen();
/**
* On the one hand, notify the controller that we've done for outbound
* connections. On the other hand, we do nothing for inbound connections.
*/
NS_ENSURE_TRUE_VOID(mController);
mController->OnDisconnect(aErrorStr);
mController = nullptr;
}
NS_IMPL_ISUPPORTS1(BluetoothHfpManager, nsIObserver) NS_IMPL_ISUPPORTS1(BluetoothHfpManager, nsIObserver)

Просмотреть файл

@ -61,22 +61,26 @@ public:
static BluetoothHfpManager* Get(); static BluetoothHfpManager* Get();
~BluetoothHfpManager(); ~BluetoothHfpManager();
// The following functions are inherited from BluetoothSocketObserver
virtual void ReceiveSocketData( virtual void ReceiveSocketData(
BluetoothSocket* aSocket, BluetoothSocket* aSocket,
nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage) MOZ_OVERRIDE; nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage) MOZ_OVERRIDE;
virtual void OnConnectSuccess(BluetoothSocket* aSocket) MOZ_OVERRIDE; virtual void OnSocketConnectSuccess(BluetoothSocket* aSocket) MOZ_OVERRIDE;
virtual void OnConnectError(BluetoothSocket* aSocket) MOZ_OVERRIDE; virtual void OnSocketConnectError(BluetoothSocket* aSocket) MOZ_OVERRIDE;
virtual void OnDisconnect(BluetoothSocket* aSocket) MOZ_OVERRIDE; virtual void OnSocketDisconnect(BluetoothSocket* aSocket) MOZ_OVERRIDE;
// The following functions are inherited from BluetoothProfileManagerBase
virtual void OnGetServiceChannel(const nsAString& aDeviceAddress, virtual void OnGetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid, const nsAString& aServiceUuid,
int aChannel) MOZ_OVERRIDE; int aChannel) MOZ_OVERRIDE;
virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) MOZ_OVERRIDE; virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) MOZ_OVERRIDE;
virtual void GetAddress(nsAString& aDeviceAddress) MOZ_OVERRIDE; virtual void GetAddress(nsAString& aDeviceAddress) MOZ_OVERRIDE;
virtual void Connect(const nsAString& aDeviceAddress,
BluetoothProfileController* aController) MOZ_OVERRIDE;
virtual void Disconnect(BluetoothProfileController* aController) MOZ_OVERRIDE;
virtual void OnConnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
virtual void OnDisconnect(const nsAString& AErrorStr) MOZ_OVERRIDE;
void Connect(const nsAString& aDeviceAddress,
const bool aIsHandsfree,
BluetoothReplyRunnable* aRunnable);
void Disconnect();
bool Listen(); bool Listen();
bool ConnectSco(BluetoothReplyRunnable* aRunnable = nullptr); bool ConnectSco(BluetoothReplyRunnable* aRunnable = nullptr);
bool DisconnectSco(); bool DisconnectSco();
@ -148,6 +152,7 @@ private:
nsTArray<Call> mCurrentCallArray; nsTArray<Call> mCurrentCallArray;
nsAutoPtr<BluetoothTelephonyListener> mListener; nsAutoPtr<BluetoothTelephonyListener> mListener;
nsRefPtr<BluetoothReplyRunnable> mRunnable; nsRefPtr<BluetoothReplyRunnable> mRunnable;
BluetoothProfileController* mController;
nsRefPtr<BluetoothReplyRunnable> mScoRunnable; nsRefPtr<BluetoothReplyRunnable> mScoRunnable;
// If a connection has been established, mSocket will be the socket // If a connection has been established, mSocket will be the socket

Просмотреть файл

@ -23,6 +23,7 @@
#include "nsIObserver.h" #include "nsIObserver.h"
BEGIN_BLUETOOTH_NAMESPACE BEGIN_BLUETOOTH_NAMESPACE
class BluetoothProfileController;
class BluetoothProfileManagerBase : public nsIObserver class BluetoothProfileManagerBase : public nsIObserver
{ {
@ -31,8 +32,35 @@ public:
const nsAString& aServiceUuid, const nsAString& aServiceUuid,
int aChannel) = 0; int aChannel) = 0;
virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) = 0; virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) = 0;
/**
* Returns the address of the connected device.
*/
virtual void GetAddress(nsAString& aDeviceAddress) = 0; virtual void GetAddress(nsAString& aDeviceAddress) = 0;
/**
* Returns true if the profile is connected.
*/
virtual bool IsConnected() = 0; virtual bool IsConnected() = 0;
/**
* Connect to a specific remote device. When it has been done, the
* callback "OnConnect" will be invoked.
*/
virtual void Connect(const nsAString& aDeviceAddress,
BluetoothProfileController* aController) = 0;
/**
* Close the socket and then invoke the callback "OnDisconnect".
*/
virtual void Disconnect(BluetoothProfileController* aController) = 0;
/**
* If it establishes/releases a connection successfully, the error string
* will be empty. Otherwise, the error string shows the failure reason.
*/
virtual void OnConnect(const nsAString& aErrorStr) = 0;
virtual void OnDisconnect(const nsAString& aErrorStr) = 0;
}; };
END_BLUETOOTH_NAMESPACE END_BLUETOOTH_NAMESPACE