Bug 820143 - implemented Calling Line Identification (CLI), r=gyeh

This commit is contained in:
Eric Chou 2012-12-17 23:24:35 +08:00
parent d81584a36d
commit 093aeb72ad
4 changed files with 134 additions and 58 deletions

View File

@ -34,6 +34,14 @@
#define TOA_UNKNOWN 0x81
#define TOA_INTERNATIONAL 0x91
/**
* These constants are used in result code such as +CLIP and +CCWA. The value
* of these constants is the same as TOA_INTERNATIONAL/TOA_UNKNOWN defined in
* ril_consts.js
*/
#define TOA_UNKNOWN 0x81
#define TOA_INTERNATIONAL 0x91
using namespace mozilla;
using namespace mozilla::ipc;
USING_BLUETOOTH_NAMESPACE
@ -216,7 +224,9 @@ BluetoothHfpManagerObserver::Observe(nsISupports* aSubject,
class SendRingIndicatorTask : public Task
{
public:
SendRingIndicatorTask()
SendRingIndicatorTask(const char* aNumber, int aType = TOA_UNKNOWN)
: mNumber(aNumber)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread());
}
@ -231,15 +241,27 @@ public:
NS_WARNING("BluetoothHfpManager no longer exists, cannot send ring!");
return;
}
gBluetoothHfpManager->SendLine("RING");
if (!mNumber.IsEmpty()) {
nsAutoCString resultCode("+CLIP: \"");
resultCode += mNumber;
resultCode += "\",";
resultCode.AppendInt(mType);
gBluetoothHfpManager->SendLine(resultCode.get());
}
MessageLoop::current()->
PostDelayedTask(FROM_HERE,
new SendRingIndicatorTask(),
new SendRingIndicatorTask(mNumber.get(), mType),
sRingInterval);
return;
}
private:
nsCString mNumber;
int mType;
};
void
@ -517,36 +539,43 @@ BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
{
MOZ_ASSERT(NS_IsMainThread());
const char* msg = (const char*)aMessage->mData;
int currentCallState = mCurrentCallStateArray[mCurrentCallIndex];
nsAutoCString msg((const char*)aMessage->mData);
msg.StripWhitespace();
nsTArray<nsCString> atCommandValues;
// For more information, please refer to 4.34.1 "Bluetooth Defined AT
// Capabilities" in Bluetooth hands-free profile 1.6
if (!strncmp(msg, "AT+BRSF=", 8)) {
if (msg.Find("AT+BRSF=") != -1) {
SendCommand("+BRSF: ", 23);
SendLine("OK");
} else if (!strncmp(msg, "AT+CIND=?", 9)) {
} else if (msg.Find("AT+CIND=?") != -1) {
// Asking for CIND range
SendCommand("+CIND: ", 0);
SendLine("OK");
} else if (!strncmp(msg, "AT+CIND?", 8)) {
} else if (msg.Find("AT+CIND?") != -1) {
// Asking for CIND value
SendCommand("+CIND: ", 1);
SendLine("OK");
} else if (!strncmp(msg, "AT+CMER=", 8)) {
// SLC establishment
SendLine("OK");
} else if (!strncmp(msg, "AT+CHLD=?", 9)) {
} else if (msg.Find("AT+CMER=") != -1) {
/**
* SLC establishment is done when AT+CMER has been received.
* Do nothing but respond with "OK".
*/
} else if (msg.Find("AT+CHLD=?") != -1) {
SendLine("+CHLD: (1,2)");
SendLine("OK");
} else if (!strncmp(msg, "AT+CHLD=", 8)) {
int length = strlen(msg) - 9;
nsAutoCString chldString(nsDependentCSubstring(msg+8, length));
} else if (msg.Find("AT+CHLD=") != -1) {
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+VGS=]");
goto respond_with_ok;
}
nsresult rv;
int chld = chldString.ToInteger(&rv);
int chld = atCommandValues[0].ToInteger(&rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to extract volume value from bluetooth headset!");
goto respond_with_ok;
}
switch(chld) {
@ -564,23 +593,25 @@ BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
#endif
break;
}
SendLine("OK");
} else if (!strncmp(msg, "AT+VGS=", 7)) {
} else if (msg.Find("AT+VGS=") != -1) {
// Adjust volume by headset
mReceiveVgsFlag = true;
ParseAtCommand(msg, 7, atCommandValues);
int length = strlen(msg) - 8;
nsAutoCString vgsString(nsDependentCSubstring(msg+7, length));
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+VGS=]");
goto respond_with_ok;
}
nsresult rv;
int newVgs = vgsString.ToInteger(&rv);
int newVgs = atCommandValues[0].ToInteger(&rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to extract volume value from bluetooth headset!");
goto respond_with_ok;
}
if (newVgs == mCurrentVgs) {
SendLine("OK");
return;
goto respond_with_ok;
}
#ifdef DEBUG
@ -591,34 +622,36 @@ BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
data.AppendInt(newVgs);
os->NotifyObservers(nullptr, "bluetooth-volume-change", data.get());
SendLine("OK");
} else if (!strncmp(msg, "AT+BLDN", 7)) {
} else if (msg.Find("AT+BLDN") != -1) {
NotifyDialer(NS_LITERAL_STRING("BLDN"));
SendLine("OK");
} else if (!strncmp(msg, "ATA", 3)) {
} else if (msg.Find("ATA") != -1) {
NotifyDialer(NS_LITERAL_STRING("ATA"));
SendLine("OK");
} else if (!strncmp(msg, "AT+CHUP", 7)) {
} else if (msg.Find("AT+CHUP") != -1) {
NotifyDialer(NS_LITERAL_STRING("CHUP"));
SendLine("OK");
} else if (!strncmp(msg, "ATD>", 4)) {
} else if (msg.Find("ATD>") != -1) {
// Currently, we don't support memory dialing in Dialer app
SendLine("ERROR");
} else if (!strncmp(msg, "ATD", 3)) {
} else if (msg.Find("ATD") != -1) {
nsAutoCString message(msg), newMsg;
int end = message.FindChar(';');
if (end < 0) {
NS_WARNING("Could't get the value of command [ATD]");
SendLine("OK");
return;
goto respond_with_ok;
}
newMsg += nsDependentCSubstring(message, 0, end);
NotifyDialer(NS_ConvertUTF8toUTF16(newMsg));
SendLine("OK");
} else if (!strncmp(msg, "AT+CKPD", 7)) {
// For Headset
} else if (msg.Find("AT+CLIP=") != -1) {
ParseAtCommand(msg, 8, atCommandValues);
if (atCommandValues.IsEmpty()) {
NS_WARNING("Could't get the value of command [AT+CLIP=]");
goto respond_with_ok;
}
mCLIP = (atCommandValues[0].EqualsLiteral("1"));
} else if (msg.Find("AT+CKPD") != -1) {
// For Headset Profile (HSP)
switch (currentCallState) {
case nsIRadioInterfaceLayer::CALL_STATE_INCOMING:
NotifyDialer(NS_LITERAL_STRING("ATA"));
@ -637,8 +670,7 @@ BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
#endif
break;
}
SendLine("OK");
} else if (!strncmp(msg, "AT+CNUM", 7)) {
} else if (msg.Find("AT+CNUM") != -1) {
if (!mMsisdn.IsEmpty()) {
nsAutoCString message("+CNUM: ,\"");
message += NS_ConvertUTF16toUTF8(mMsisdn).get();
@ -647,7 +679,6 @@ BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
message += ",,4";
SendLine(message.get());
}
SendLine("OK");
} else {
#ifdef DEBUG
nsCString warningMsg;
@ -655,8 +686,11 @@ BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
warningMsg.Append(msg);
NS_WARNING(warningMsg.get());
#endif
SendLine("OK");
}
respond_with_ok:
// We always respond to remote device with "OK" in general cases.
SendLine("OK");
}
bool
@ -815,12 +849,13 @@ BluetoothHfpManager::SendCommand(const char* aCommand, const int aValue)
}
void
BluetoothHfpManager::SetupCIND(int aCallIndex, int aCallState, bool aInitial)
BluetoothHfpManager::SetupCIND(int aCallIndex, int aCallState,
const char* aNumber, bool aInitial)
{
nsRefPtr<nsRunnable> sendRingTask;
nsString address;
while (aCallIndex >= mCurrentCallStateArray.Length()) {
while (aCallIndex >= (int)mCurrentCallStateArray.Length()) {
mCurrentCallStateArray.AppendElement((int)nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED);
}
@ -836,8 +871,21 @@ BluetoothHfpManager::SetupCIND(int aCallIndex, int aCallState, bool aInitial)
if (!mCurrentCallIndex) {
// Start sending RING indicator to HF
sStopSendingRingFlag = false;
MessageLoop::current()->PostTask(FROM_HERE,
new SendRingIndicatorTask());
if (!mCLIP) {
MessageLoop::current()->PostTask(FROM_HERE,
new SendRingIndicatorTask(""));
} else {
// Same logic as implementation in ril_worker.js
int type = TOA_UNKNOWN;
if (aNumber && strlen(aNumber) > 0 && aNumber[0] == '+') {
type = TOA_INTERNATIONAL;
}
MessageLoop::current()->PostTask(FROM_HERE,
new SendRingIndicatorTask(aNumber, type));
}
}
break;
case nsIRadioInterfaceLayer::CALL_STATE_DIALING:
@ -921,18 +969,18 @@ BluetoothHfpManager::SetupCIND(int aCallIndex, int aCallState, bool aInitial)
// Find the first non-disconnected call (like connected, held),
// and update mCurrentCallIndex
int c;
for (c = 1; c < mCurrentCallStateArray.Length(); c++) {
for (c = 1; c < (int)mCurrentCallStateArray.Length(); c++) {
if (mCurrentCallStateArray[c] != nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED) {
mCurrentCallIndex = c;
break;
}
}
// There is no call
if (c == mCurrentCallStateArray.Length()) {
// There is no call
if (c == (int)mCurrentCallStateArray.Length()) {
mCurrentCallIndex = 0;
CloseScoSocket();
}
}
}
}
break;
@ -964,7 +1012,7 @@ void
BluetoothHfpManager::EnumerateCallState(int aCallIndex, int aCallState,
const char* aNumber, bool aIsActive)
{
SetupCIND(aCallIndex, aCallState, true);
SetupCIND(aCallIndex, aCallState, aNumber, true);
if (sCINDItems[CINDType::CALL].value == CallState::IN_PROGRESS ||
sCINDItems[CINDType::CALLSETUP].value == CallSetupState::OUTGOING ||
@ -988,7 +1036,7 @@ BluetoothHfpManager::CallStateChanged(int aCallIndex, int aCallState,
return;
}
SetupCIND(aCallIndex, aCallState, false);
SetupCIND(aCallIndex, aCallState, aNumber, false);
}
void
@ -1051,4 +1099,5 @@ BluetoothHfpManager::OnDisconnect()
sCINDItems[CINDType::CALL].value = CallState::NO_CALL;
sCINDItems[CINDType::CALLSETUP].value = CallSetupState::NO_CALLSETUP;
sCINDItems[CINDType::CALLHELD].value = CallHeldState::NO_CALLHELD;
mCLIP = false;
}

View File

@ -34,7 +34,8 @@ public:
const char* aNumber, bool aIsActive);
void EnumerateCallState(int aCallIndex, int aCallState,
const char* aNumber, bool aIsActive);
void SetupCIND(int aCallIndex, int aCallState, bool aInitial);
void SetupCIND(int aCallIndex, int aCallState,
const char* aPhoneNumber, bool aInitial);
bool Listen();
void SetVolume(int aVolume);
@ -55,6 +56,7 @@ private:
int mCurrentVgs;
int mCurrentCallIndex;
bool mCLIP;
bool mReceiveVgsFlag;
nsString mDevicePath;
nsString mMsisdn;

View File

@ -136,5 +136,25 @@ DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
}
}
END_BLUETOOTH_NAMESPACE
void
ParseAtCommand(const nsACString& aAtCommand, const int aStart,
nsTArray<nsCString>& aRetValues)
{
int length = aAtCommand.Length();
int begin = aStart;
for (int i = aStart; i < length; ++i) {
// Use ',' as separator
if (aAtCommand[i] == ',') {
nsCString tmp(nsDependentCSubstring(aAtCommand, begin, i - begin));
aRetValues.AppendElement(tmp);
begin = i + 1;
}
}
nsCString tmp(nsDependentCSubstring(aAtCommand, begin));
aRetValues.AppendElement(tmp);
}
END_BLUETOOTH_NAMESPACE

View File

@ -8,6 +8,7 @@
#define mozilla_dom_bluetooth_bluetoothutils_h__
#include "BluetoothCommon.h"
#include "nsTArray.h"
struct JSContext;
struct JSObject;
@ -39,6 +40,10 @@ DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
const BluetoothValue& aValue,
const nsAString& aErrorStr);
void
ParseAtCommand(const nsACString& aAtCommand, const int aStart,
nsTArray<nsCString>& aRetValues);
END_BLUETOOTH_NAMESPACE
#endif