Bug 1172914: Minimize Bluetooth v1/v2 duplication in BluetoothServiceBluedroid.cpp, r=btian

This commit is contained in:
Thomas Zimmermann 2015-06-16 17:28:07 +02:00
parent 064a48406f
commit 000662f84d

View File

@ -64,7 +64,6 @@
} while(0)
#ifndef MOZ_B2G_BT_API_V1
#define ENSURE_GATT_MGR_IS_READY_VOID(gatt, runnable) \
do { \
if (!gatt) { \
@ -73,6 +72,18 @@
return; \
} \
} while(0)
#else
// Missing in Bluetooth v1
#endif
#ifndef MOZ_B2G_BT_API_V1
// Missing in Bluetooth v2
#else
// Audio: Major service class = 0x100 (Bit 21 is set)
#define SET_AUDIO_BIT(cod) (cod |= 0x200000)
// Rendering: Major service class = 0x20 (Bit 18 is set)
#define SET_RENDERING_BIT(cod) (cod |= 0x40000)
#endif
using namespace mozilla;
using namespace mozilla::ipc;
@ -80,35 +91,53 @@ USING_BLUETOOTH_NAMESPACE
static nsString sAdapterBdAddress;
static nsString sAdapterBdName;
static bool sAdapterDiscoverable(false);
static bool sAdapterDiscovering(false);
static bool sAdapterEnabled(false);
// InfallibleTArray is an alias for nsTArray.
static InfallibleTArray<nsString> sAdapterBondedAddressArray;
static BluetoothInterface* sBtInterface;
static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
static nsTArray<int> sRequestedDeviceCountArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
static bool sIsRestart(false);
static bool sIsFirstTimeToggleOffBt(false);
#ifndef MOZ_B2G_BT_API_V1
static bool sAdapterEnabled(false);
// Use a static hash table to keep the name of remote device during the pairing
// procedure. In this manner, BT service and adapter can get the name of paired
// device name when bond state changed.
// The hash Key is BD address, the Value is remote BD name.
static nsDataHashtable<nsStringHashKey, nsString> sPairingNameTable;
static BluetoothInterface* sBtInterface;
static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
static nsTArray<int> sRequestedDeviceCountArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sFetchUuidsRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
static bool sIsRestart(false);
static bool sIsFirstTimeToggleOffBt(false);
#else
// Missing in Bluetooth v1
#endif
/**
* Static callback functions
#ifndef MOZ_B2G_BT_API_V1
// Missing in Bluetooth v2
#else
static uint32_t sAdapterDiscoverableTimeout(0);
#endif
/*
* Static methods
*/
ControlPlayStatus
BluetoothServiceBluedroid::PlayStatusStringToControlPlayStatus(
const nsAString& aPlayStatus)
@ -131,9 +160,129 @@ BluetoothServiceBluedroid::PlayStatusStringToControlPlayStatus(
return playStatus;
}
/**
* Static functions
*/
#ifndef MOZ_B2G_BT_API_V1
// Missing in Bluetooth v2
#else
void
BluetoothServiceBluedroid::ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
{
switch ((aClass & 0x1f00) >> 8) {
case 0x01:
aRetIcon.AssignLiteral("computer");
break;
case 0x02:
switch ((aClass & 0xfc) >> 2) {
case 0x01:
case 0x02:
case 0x03:
case 0x05:
aRetIcon.AssignLiteral("phone");
break;
case 0x04:
aRetIcon.AssignLiteral("modem");
break;
}
break;
case 0x03:
aRetIcon.AssignLiteral("network-wireless");
break;
case 0x04:
switch ((aClass & 0xfc) >> 2) {
case 0x01:
case 0x02:
case 0x06:
aRetIcon.AssignLiteral("audio-card");
break;
case 0x0b:
case 0x0c:
case 0x0d:
aRetIcon.AssignLiteral("camera-video");
break;
default:
aRetIcon.AssignLiteral("audio-card");
break;
}
break;
case 0x05:
switch ((aClass & 0xc0) >> 6) {
case 0x00:
switch ((aClass && 0x1e) >> 2) {
case 0x01:
case 0x02:
aRetIcon.AssignLiteral("input-gaming");
break;
}
break;
case 0x01:
aRetIcon.AssignLiteral("input-keyboard");
break;
case 0x02:
switch ((aClass && 0x1e) >> 2) {
case 0x05:
aRetIcon.AssignLiteral("input-tablet");
break;
default:
aRetIcon.AssignLiteral("input-mouse");
break;
}
}
break;
case 0x06:
if (aClass & 0x80) {
aRetIcon.AssignLiteral("printer");
break;
}
if (aClass & 0x20) {
aRetIcon.AssignLiteral("camera-photo");
break;
}
break;
}
if (aRetIcon.IsEmpty()) {
if (HAS_AUDIO(aClass)) {
/**
* Property 'Icon' may be missed due to CoD of major class is TOY(0x08).
* But we need to assign Icon as audio-card if service class is 'Audio'.
* This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification
* defines that service class is 'Audio' can be considered as HFP HF.
*/
aRetIcon.AssignLiteral("audio-card");
} else {
BT_LOGR("No icon to match class: %x", aClass);
}
}
}
static void
ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
BluetoothStatus aStatusCode, const nsAString& aCustomMsg)
{
MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr");
BT_LOGR("error code(%d)", aStatusCode);
nsAutoString replyError;
replyError.Assign(aCustomMsg);
if (aStatusCode == STATUS_BUSY) {
replyError.AppendLiteral(":BT_STATUS_BUSY");
} else if (aStatusCode == STATUS_NOT_READY) {
replyError.AppendLiteral(":BT_STATUS_NOT_READY");
} else if (aStatusCode == STATUS_DONE) {
replyError.AppendLiteral(":BT_STATUS_DONE");
} else if (aStatusCode == STATUS_AUTH_FAILURE) {
replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE");
} else if (aStatusCode == STATUS_RMT_DEV_DOWN) {
replyError.AppendLiteral(":BT_STATUS_RMT_DEV_DOWN");
} else if (aStatusCode == STATUS_FAIL) {
replyError.AppendLiteral(":BT_STATUS_FAIL");
}
DispatchReplyError(aBluetoothReplyRunnable, replyError);
}
#endif
class BluetoothServiceBluedroid::EnableResultHandler final
: public BluetoothResultHandler
{
@ -194,7 +343,11 @@ public:
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
BluetoothHfpManager::InitHfpInterface,
BluetoothA2dpManager::InitA2dpInterface,
#ifndef MOZ_B2G_BT_API_V1
BluetoothGattManager::InitGattInterface
#else
// Missing in Bluetooth v1
#endif
};
MOZ_ASSERT(NS_IsMainThread());
@ -254,7 +407,12 @@ public:
BT_LOGR("BluetoothInterface::Disable failed: %d", aStatus);
#ifndef MOZ_B2G_BT_API_V1
BluetoothService::AcknowledgeToggleBt(true);
#else
// Always make progress; even on failures
BluetoothService::AcknowledgeToggleBt(false);
#endif
}
};
@ -279,9 +437,10 @@ BluetoothServiceBluedroid::StopGonkBluetooth()
return NS_OK;
}
/**
/*
* Member functions
*/
BluetoothServiceBluedroid::BluetoothServiceBluedroid()
{
sBtInterface = BluetoothInterface::GetInstance();
@ -294,13 +453,14 @@ BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
{
}
#ifndef MOZ_B2G_BT_API_V1
nsresult
BluetoothServiceBluedroid::StartInternal(BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
// aRunnable will be a nullptr while startup
if(aRunnable) {
if (aRunnable) {
sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
}
@ -309,7 +469,7 @@ BluetoothServiceBluedroid::StartInternal(BluetoothReplyRunnable* aRunnable)
BluetoothService::AcknowledgeToggleBt(false);
// Reject Promise
if(aRunnable) {
if (aRunnable) {
DispatchReplyError(aRunnable, NS_LITERAL_STRING("StartBluetoothError"));
sChangeAdapterStateRunnableArray.RemoveElement(aRunnable);
}
@ -352,7 +512,7 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
}
// aRunnable will be a nullptr during starup and shutdown
if(aRunnable) {
if (aRunnable) {
sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
}
@ -361,7 +521,7 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
BluetoothService::AcknowledgeToggleBt(true);
// Reject Promise
if(aRunnable) {
if (aRunnable) {
DispatchReplyError(aRunnable, NS_LITERAL_STRING("StopBluetoothError"));
sChangeAdapterStateRunnableArray.RemoveElement(aRunnable);
}
@ -371,11 +531,41 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
return ret;
}
#else
nsresult
BluetoothServiceBluedroid::StartInternal()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult ret = StartGonkBluetooth();
if (NS_FAILED(ret)) {
BluetoothService::AcknowledgeToggleBt(false);
BT_LOGR("Error");
}
return ret;
}
nsresult
BluetoothServiceBluedroid::StopInternal()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult ret = StopGonkBluetooth();
if (NS_FAILED(ret)) {
BluetoothService::AcknowledgeToggleBt(true);
BT_LOGR("Error");
}
return ret;
}
#endif
//
// GATT Client
//
#ifndef MOZ_B2G_BT_API_V1
void
BluetoothServiceBluedroid::StartLeScanInternal(
const nsTArray<nsString>& aServiceUuids,
@ -584,367 +774,7 @@ BluetoothServiceBluedroid::GattClientWriteDescriptorValueInternal(
aDescriptorId, aValue, aRunnable);
}
#else
// Audio: Major service class = 0x100 (Bit 21 is set)
#define SET_AUDIO_BIT(cod) (cod |= 0x200000)
// Rendering: Major service class = 0x20 (Bit 18 is set)
#define SET_RENDERING_BIT(cod) (cod |= 0x40000)
using namespace mozilla;
using namespace mozilla::ipc;
USING_BLUETOOTH_NAMESPACE
static nsString sAdapterBdAddress;
static nsString sAdapterBdName;
static InfallibleTArray<nsString> sAdapterBondedAddressArray;
static BluetoothInterface* sBtInterface;
static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
static nsTArray<int> sRequestedDeviceCountArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
static bool sAdapterDiscoverable(false);
static bool sAdapterDiscovering(false);
static bool sIsRestart(false);
static bool sIsFirstTimeToggleOffBt(false);
static uint32_t sAdapterDiscoverableTimeout(0);
/**
* Static callback functions
*/
void
BluetoothServiceBluedroid::ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
{
switch ((aClass & 0x1f00) >> 8) {
case 0x01:
aRetIcon.AssignLiteral("computer");
break;
case 0x02:
switch ((aClass & 0xfc) >> 2) {
case 0x01:
case 0x02:
case 0x03:
case 0x05:
aRetIcon.AssignLiteral("phone");
break;
case 0x04:
aRetIcon.AssignLiteral("modem");
break;
}
break;
case 0x03:
aRetIcon.AssignLiteral("network-wireless");
break;
case 0x04:
switch ((aClass & 0xfc) >> 2) {
case 0x01:
case 0x02:
case 0x06:
aRetIcon.AssignLiteral("audio-card");
break;
case 0x0b:
case 0x0c:
case 0x0d:
aRetIcon.AssignLiteral("camera-video");
break;
default:
aRetIcon.AssignLiteral("audio-card");
break;
}
break;
case 0x05:
switch ((aClass & 0xc0) >> 6) {
case 0x00:
switch ((aClass && 0x1e) >> 2) {
case 0x01:
case 0x02:
aRetIcon.AssignLiteral("input-gaming");
break;
}
break;
case 0x01:
aRetIcon.AssignLiteral("input-keyboard");
break;
case 0x02:
switch ((aClass && 0x1e) >> 2) {
case 0x05:
aRetIcon.AssignLiteral("input-tablet");
break;
default:
aRetIcon.AssignLiteral("input-mouse");
break;
}
}
break;
case 0x06:
if (aClass & 0x80) {
aRetIcon.AssignLiteral("printer");
break;
}
if (aClass & 0x20) {
aRetIcon.AssignLiteral("camera-photo");
break;
}
break;
}
if (aRetIcon.IsEmpty()) {
if (HAS_AUDIO(aClass)) {
/**
* Property 'Icon' may be missed due to CoD of major class is TOY(0x08).
* But we need to assign Icon as audio-card if service class is 'Audio'.
* This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification
* defines that service class is 'Audio' can be considered as HFP HF.
*/
aRetIcon.AssignLiteral("audio-card");
} else {
BT_LOGR("No icon to match class: %x", aClass);
}
}
}
ControlPlayStatus
BluetoothServiceBluedroid::PlayStatusStringToControlPlayStatus(
const nsAString& aPlayStatus)
{
ControlPlayStatus playStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
if (aPlayStatus.EqualsLiteral("STOPPED")) {
playStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
} else if (aPlayStatus.EqualsLiteral("PLAYING")) {
playStatus = ControlPlayStatus::PLAYSTATUS_PLAYING;
} else if (aPlayStatus.EqualsLiteral("PAUSED")) {
playStatus = ControlPlayStatus::PLAYSTATUS_PAUSED;
} else if (aPlayStatus.EqualsLiteral("FWD_SEEK")) {
playStatus = ControlPlayStatus::PLAYSTATUS_FWD_SEEK;
} else if (aPlayStatus.EqualsLiteral("REV_SEEK")) {
playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK;
} else if (aPlayStatus.EqualsLiteral("ERROR")) {
playStatus = ControlPlayStatus::PLAYSTATUS_ERROR;
}
return playStatus;
}
/**
* Static functions
*/
class BluetoothServiceBluedroid::EnableResultHandler final
: public BluetoothResultHandler
{
public:
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR("BluetoothInterface::Enable failed: %d", aStatus);
BluetoothService::AcknowledgeToggleBt(false);
}
};
/* |ProfileInitResultHandler| collect the results of all profile
* result handlers and calls |Proceed| after all results handlers
* have been run.
*/
class BluetoothServiceBluedroid::ProfileInitResultHandler final
: public BluetoothProfileResultHandler
{
public:
ProfileInitResultHandler(unsigned char aNumProfiles)
: mNumProfiles(aNumProfiles)
{
MOZ_ASSERT(mNumProfiles);
}
void Init() override
{
if (!(--mNumProfiles)) {
Proceed();
}
}
void OnError(nsresult aResult) override
{
if (!(--mNumProfiles)) {
Proceed();
}
}
private:
void Proceed() const
{
sBtInterface->Enable(new EnableResultHandler());
}
unsigned char mNumProfiles;
};
class BluetoothServiceBluedroid::InitResultHandler final
: public BluetoothResultHandler
{
public:
void Init() override
{
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
BluetoothHfpManager::InitHfpInterface,
BluetoothA2dpManager::InitA2dpInterface
};
MOZ_ASSERT(NS_IsMainThread());
// Register all the bluedroid callbacks before enable() get called
// It is required to register a2dp callbacks before a2dp media task starts up.
// If any interface cannot be initialized, turn on bluetooth core anyway.
nsRefPtr<ProfileInitResultHandler> res =
new ProfileInitResultHandler(MOZ_ARRAY_LENGTH(sInitManager));
for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sInitManager); ++i) {
sInitManager[i](res);
}
}
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR("BluetoothInterface::Init failed: %d", aStatus);
sBtInterface = nullptr;
BluetoothService::AcknowledgeToggleBt(false);
}
};
nsresult
BluetoothServiceBluedroid::StartGonkBluetooth()
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if (bs->IsEnabled()) {
// Keep current enable status
BluetoothService::AcknowledgeToggleBt(true);
return NS_OK;
}
sBtInterface->Init(reinterpret_cast<BluetoothServiceBluedroid*>(bs),
new InitResultHandler());
return NS_OK;
}
class BluetoothServiceBluedroid::DisableResultHandler final
: public BluetoothResultHandler
{
public:
void OnError(BluetoothStatus aStatus) override
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR("BluetoothInterface::Disable failed: %d", aStatus);
// Always make progress; even on failures
BluetoothService::AcknowledgeToggleBt(false);
}
};
nsresult
BluetoothServiceBluedroid::StopGonkBluetooth()
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if (!bs->IsEnabled()) {
// Keep current enable status
BluetoothService::AcknowledgeToggleBt(false);
return NS_OK;
}
sBtInterface->Disable(new DisableResultHandler());
return NS_OK;
}
static void
ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
BluetoothStatus aStatusCode, const nsAString& aCustomMsg)
{
MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr");
BT_LOGR("error code(%d)", aStatusCode);
nsAutoString replyError;
replyError.Assign(aCustomMsg);
if (aStatusCode == STATUS_BUSY) {
replyError.AppendLiteral(":BT_STATUS_BUSY");
} else if (aStatusCode == STATUS_NOT_READY) {
replyError.AppendLiteral(":BT_STATUS_NOT_READY");
} else if (aStatusCode == STATUS_DONE) {
replyError.AppendLiteral(":BT_STATUS_DONE");
} else if (aStatusCode == STATUS_AUTH_FAILURE) {
replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE");
} else if (aStatusCode == STATUS_RMT_DEV_DOWN) {
replyError.AppendLiteral(":BT_STATUS_RMT_DEV_DOWN");
} else if (aStatusCode == STATUS_FAIL) {
replyError.AppendLiteral(":BT_STATUS_FAIL");
}
DispatchReplyError(aBluetoothReplyRunnable, replyError);
}
/**
* Member functions
*/
BluetoothServiceBluedroid::BluetoothServiceBluedroid()
{
sBtInterface = BluetoothInterface::GetInstance();
if (!sBtInterface) {
BT_LOGR("Error! Failed to get instance of bluetooth interface");
}
}
BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
{
}
nsresult
BluetoothServiceBluedroid::StartInternal()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult ret = StartGonkBluetooth();
if (NS_FAILED(ret)) {
BluetoothService::AcknowledgeToggleBt(false);
BT_LOGR("Error");
}
return ret;
}
nsresult
BluetoothServiceBluedroid::StopInternal()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult ret = StopGonkBluetooth();
if (NS_FAILED(ret)) {
BluetoothService::AcknowledgeToggleBt(true);
BT_LOGR("Error");
}
return ret;
}
// Missing in Bluetooth v1
#endif
#ifndef MOZ_B2G_BT_API_V1
@ -2826,7 +2656,6 @@ BluetoothServiceBluedroid::BondStateChangedNotification(
BluetoothStatus aStatus, const nsAString& aRemoteBdAddr,
BluetoothBondState aState)
{
#ifndef MOZ_B2G_BT_API_V1
MOZ_ASSERT(NS_IsMainThread());
if (aState == BOND_STATE_BONDING) {
@ -2836,6 +2665,7 @@ BluetoothServiceBluedroid::BondStateChangedNotification(
BT_LOGR("Bond state: %d status: %d", aState, aStatus);
#ifndef MOZ_B2G_BT_API_V1
bool bonded = (aState == BOND_STATE_BONDED);
if (aStatus != STATUS_SUCCESS) {
if (!bonded) { // Active/passive pair failed
@ -2909,13 +2739,6 @@ BluetoothServiceBluedroid::BondStateChangedNotification(
sUnbondingRunnableArray.RemoveElementAt(0);
}
#else
MOZ_ASSERT(NS_IsMainThread());
if (aState == BOND_STATE_BONDING) {
// No need to handle bonding state
return;
}
if (aState == BOND_STATE_BONDED &&
sAdapterBondedAddressArray.Contains(aRemoteBdAddr)) {
// See bug 940271 for more details about this case.