Bug 794349 - Send correct +CIND: value to HS at SLC establishment. r=qdot, a=blocking-basecamp
authorGina Yeh <gyeh@mozilla.com>
Tue, 09 Oct 2012 19:19:29 +0800
changeset 113347 d00caf574dd57c5598851d03d62ae7e01bf417ae
parent 113346 475c67cb2458cffd7314218e8841a6d9edf61c0b
child 113348 e47353b30f18e46b660158753be885b2526410c5
push id2293
push userryanvm@gmail.com
push dateSat, 13 Oct 2012 19:46:06 +0000
treeherdermozilla-aurora@a24b525c7f93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot, blocking-basecamp
bugs794349
milestone18.0a2
Bug 794349 - Send correct +CIND: value to HS at SLC establishment. r=qdot, a=blocking-basecamp
dom/bluetooth/BluetoothHfpManager.cpp
dom/bluetooth/BluetoothHfpManager.h
dom/bluetooth/BluetoothRilListener.cpp
dom/bluetooth/BluetoothRilListener.h
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -23,16 +23,18 @@
 #include "nsIRadioInterfaceLayer.h"
 #include "nsVariant.h"
 
 #include <unistd.h> /* usleep() */
 
 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
 #define BLUETOOTH_SCO_STATUS_CHANGED "bluetooth-sco-status-changed"
 #define AUDIO_VOLUME_MASTER "audio.volume.master"
+#define HANDSFREE_UUID mozilla::dom::bluetooth::BluetoothServiceUuidStr::Handsfree
+#define HEADSET_UUID mozilla::dom::bluetooth::BluetoothServiceUuidStr::Headset
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
 class mozilla::dom::bluetooth::BluetoothHfpManagerObserver : public nsIObserver
 {
 public:
@@ -173,16 +175,19 @@ CloseScoSocket()
     sco->Disconnect();
   }
 }
 
 BluetoothHfpManager::BluetoothHfpManager()
   : mCurrentVgs(-1)
   , mCurrentCallIndex(0)
   , mCurrentCallState(nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED)
+  , mCall(0)
+  , mCallSetup(0)
+  , mCallHeld(0)
 {
 }
 
 bool
 BluetoothHfpManager::Init()
 {
   sHfpObserver = new BluetoothHfpManagerObserver();
   if (!sHfpObserver->Init()) {
@@ -384,16 +389,33 @@ BluetoothHfpManager::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   gInShutdown = true;
   CloseSocket();
   gBluetoothHfpManager = nullptr;
   return NS_OK;
 }
 
+bool
+AppendIntegerToString(nsAutoCString& aString, int aValue)
+{
+  nsDiscriminatedUnion du;
+  du.mType = 0;
+  du.u.mInt8Value = aValue;
+
+  nsCString temp;
+  if (NS_FAILED(nsVariant::ConvertToACString(du, temp))) {
+    NS_WARNING("Failed to convert mCall/mCallSetup/mCallHeld to string");
+    return false;
+  }
+  aString += temp;
+  aString += ",";
+  return true;
+}
+
 // Virtual function of class SocketConsumer
 void
 BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   const char* msg = (const char*)aMessage->mData;
 
@@ -411,23 +433,28 @@ BluetoothHfpManager::ReceiveSocketData(U
     cindRange += "(\"service\",(0,1)),";
     cindRange += "(\"call\",(0,1)),";
     cindRange += "(\"callsetup\",(0-3)),";
     cindRange += "(\"callheld\",(0-2)),";
     cindRange += "(\"roam\",(0,1))";
 
     SendLine(cindRange.get());
     SendLine("OK");
-  } else if (!strncmp(msg, "AT+CIND", 7)) {
-    // FIXME - Bug 794349
-    // This value reflects current status of telephony, roaming, battery ...,
-    // so obviously fixed value must be wrong if there is an ongoing call. 
-    // Need a patch for this, but currently just using fixed value for basic 
-    // SLC establishment.
-    SendLine("+CIND: 5,5,1,0,0,0,0");
+  } else if (!strncmp(msg, "AT+CIND?", 8)) {
+    nsAutoCString cind;
+    cind += "+CIND: 5,5,1,";
+
+    if (!AppendIntegerToString(cind, mCall) ||
+        !AppendIntegerToString(cind, mCallSetup) ||
+        !AppendIntegerToString(cind, mCallHeld)) {
+      NS_WARNING("Failed to convert mCall/mCallSetup/mCallHeld to string");
+    } 
+    cind += "0";
+
+    SendLine(cind.get());
     SendLine("OK");
   } else if (!strncmp(msg, "AT+CMER=", 8)) {
     // SLC establishment
     NotifySettings(true);
     SendLine("OK");
   } else if (!strncmp(msg, "AT+CHLD=?", 9)) {
     SendLine("+CHLD: (0,1,2,3)");
     SendLine("OK");
@@ -517,21 +544,26 @@ BluetoothHfpManager::Connect(const nsASt
   if (!bs) {
     NS_WARNING("BluetoothService not available!");
     return false;
   }
   mDevicePath = aDeviceObjectPath;
 
   nsString serviceUuidStr;
   if (aIsHandsfree) {
-    serviceUuidStr = NS_ConvertUTF8toUTF16(mozilla::dom::bluetooth::BluetoothServiceUuidStr::Handsfree);
+    serviceUuidStr = NS_ConvertUTF8toUTF16(HANDSFREE_UUID);
   } else {
-    serviceUuidStr = NS_ConvertUTF8toUTF16(mozilla::dom::bluetooth::BluetoothServiceUuidStr::Headset);
+    serviceUuidStr = NS_ConvertUTF8toUTF16(HEADSET_UUID);
   }
 
+  nsCOMPtr<nsIRILContentHelper> ril =
+    do_GetService("@mozilla.org/ril/content-helper;1");
+  NS_ENSURE_TRUE(ril, NS_ERROR_UNEXPECTED);
+  ril->EnumerateCalls(mListener->GetCallback());
+
   nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
 
   nsresult rv = bs->GetSocketViaService(aDeviceObjectPath,
                                         serviceUuidStr,
                                         BluetoothSocketType::RFCOMM,
                                         true,
                                         false,
                                         this,
@@ -565,32 +597,90 @@ BluetoothHfpManager::Listen()
   return NS_FAILED(rv) ? false : true;
 }
 
 void
 BluetoothHfpManager::Disconnect()
 {
   NotifySettings(false);
   CloseSocket();
+  mCall = 0;
+  mCallSetup = 0;
+  mCallHeld = 0;
 }
 
 bool
 BluetoothHfpManager::SendLine(const char* aMessage)
 {
   const char* kHfpCrlf = "\xd\xa";
   nsAutoCString msg;
 
   msg += kHfpCrlf;
   msg += aMessage;
   msg += kHfpCrlf;
 
   return SendSocketData(msg);
 }
 
 /*
+ * EnumerateCallState will be called for each call
+ */
+void
+BluetoothHfpManager::EnumerateCallState(int aCallIndex, int aCallState,
+                                        const char* aNumber, bool aIsActive)
+{
+  // TODO: enums for mCall, mCallSetup, mCallHeld
+  /* mCall - 0: there are no calls in progress
+   *       - 1: at least one call is in progress
+   * mCallSetup - 0: not currently in call set up
+   *            - 1: an incoming call process ongoing
+   *            - 2: an outgoing call set up is ongoing
+   *            - 3: remote party being alerted in an outgoing call
+   * mCallHeld - 0: no calls held
+   *           - 1: call is placed on hold or active/held calls swapped
+   *           - 2: call o hold, no active call
+   */
+
+  if (mCallHeld == 2 && aIsActive) {
+    mCallHeld = 1;
+  }
+
+  if (mCall || mCallSetup) {
+    return;
+  }
+
+  switch (aCallState) {
+    case nsIRadioInterfaceLayer::CALL_STATE_ALERTING:
+      mCall = 1;
+      mCallSetup = 3;
+      break;
+    case nsIRadioInterfaceLayer::CALL_STATE_INCOMING:
+      mCall = 1;
+      mCallSetup = 1;
+      break;
+    case nsIRadioInterfaceLayer::CALL_STATE_CONNECTING:
+    case nsIRadioInterfaceLayer::CALL_STATE_CONNECTED:
+    case nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTING:
+    case nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED:
+    case nsIRadioInterfaceLayer::CALL_STATE_BUSY:
+      mCall = 1;
+      mCallSetup = 2;
+      break;
+    case nsIRadioInterfaceLayer::CALL_STATE_HOLDING:
+    case nsIRadioInterfaceLayer::CALL_STATE_HELD:
+    case nsIRadioInterfaceLayer::CALL_STATE_RESUMING:
+      mCall = 1;
+      mCallHeld = 2;
+    default:
+      mCall = 0;
+      mCallSetup = 0;
+  }
+}
+
+/*
  * CallStateChanged will be called whenever call status is changed, and it
  * also means we need to notify HS about the change. For more information, 
  * please refer to 4.13 ~ 4.15 in Bluetooth hands-free profile 1.6.
  */
 void
 BluetoothHfpManager::CallStateChanged(int aCallIndex, int aCallState,
                                       const char* aNumber, bool aIsActive)
 {
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -25,30 +25,35 @@ public:
   void ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage);
   bool Connect(const nsAString& aDeviceObjectPath,
                const bool aIsHandsfree,
                BluetoothReplyRunnable* aRunnable);
   void Disconnect();
   bool SendLine(const char* aMessage);
   void CallStateChanged(int aCallIndex, int aCallState,
                         const char* aNumber, bool aIsActive);
+  void EnumerateCallState(int aCallIndex, int aCallState,
+                          const char* aNumber, bool aIsActive);
   bool Listen();
 
 private:
   friend class BluetoothHfpManagerObserver;
   BluetoothHfpManager();
   nsresult HandleVolumeChanged(const nsAString& aData);
   nsresult HandleShutdown();
   bool Init();
   void Cleanup();
   void NotifyDialer(const nsAString& aCommand);
   void NotifySettings(const bool aConnected);
 
   int mCurrentVgs;
   int mCurrentCallIndex;
   int mCurrentCallState;
+  int mCall;
+  int mCallSetup;
+  int mCallHeld;
   nsAutoPtr<BluetoothRilListener> mListener;
   nsString mDevicePath;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -39,16 +39,19 @@ BluetoothRILTelephonyCallback::CallState
 
 NS_IMETHODIMP
 BluetoothRILTelephonyCallback::EnumerateCallState(uint32_t aCallIndex,
                                                   uint16_t aCallState,
                                                   const nsAString_internal& aNumber,
                                                   bool aIsActive,
                                                   bool* aResult)
 {
+  BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+  hfp->EnumerateCallState(aCallIndex, aCallState,
+                          NS_ConvertUTF16toUTF8(aNumber).get(), aIsActive);
   *aResult = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BluetoothRILTelephonyCallback::NotifyError(int32_t aCallIndex,
                                            const nsAString& aError)
 {
@@ -82,8 +85,14 @@ BluetoothRilListener::StopListening()
     NS_ERROR("No RIL Service!");
     return false;
   }
 
   nsresult rv = ril->UnregisterTelephonyCallback(mRILTelephonyCallback);
 
   return NS_FAILED(rv) ? false : true;
 }
+
+nsIRILTelephonyCallback*
+BluetoothRilListener::GetCallback()
+{
+  return mRILTelephonyCallback;
+}
--- a/dom/bluetooth/BluetoothRilListener.h
+++ b/dom/bluetooth/BluetoothRilListener.h
@@ -17,15 +17,17 @@ BEGIN_BLUETOOTH_NAMESPACE
 class BluetoothRilListener
 {
 public:
   BluetoothRilListener();
 
   bool StartListening();
   bool StopListening();
 
+  nsIRILTelephonyCallback* GetCallback();
+
 private:
   nsCOMPtr<nsIRILTelephonyCallback> mRILTelephonyCallback;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif