Bug 820157 - Patch 1: bluetooth Hfp not sending status updates, r=echou
authorGina Yeh <gyeh@mozilla.com>
Thu, 20 Dec 2012 15:28:51 +0800
changeset 125715 ebad7aef8c52ef6ea023a6dbab9dfb3a62ef77ab
parent 125714 6bec2e9a2371184340a27ce405a1288da282d865
child 125716 bb90ec82052beeae0941949e907ae92bfea926fb
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechou
bugs820157
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 820157 - Patch 1: bluetooth Hfp not sending status updates, r=echou
dom/bluetooth/BluetoothHfpManager.cpp
dom/bluetooth/BluetoothHfpManager.h
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -18,39 +18,49 @@
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsIAudioManager.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsIRadioInterfaceLayer.h"
+#include "nsRadioInterfaceLayer.h"
 
 #include <unistd.h> /* usleep() */
 
 #define AUDIO_VOLUME_BT_SCO "audio.volume.bt_sco"
 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
 #define MOBILE_CONNECTION_ICCINFO_CHANGED "mobile-connection-iccinfo-changed"
-#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
+#define MOBILE_CONNECTION_VOICE_CHANGED "mobile-connection-voice-changed"
 
 #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
 
+namespace {
+  StaticRefPtr<BluetoothHfpManager> gBluetoothHfpManager;
+  StaticRefPtr<BluetoothHfpManagerObserver> sHfpObserver;
+  bool gInShutdown = false;
+  static bool sStopSendingRingFlag = true;
+
+  static int sRingInterval = 3000; //unit: ms
+} // anonymous namespace
+
 /* CallState for sCINDItems[CINDType::CALL].value
  * - NO_CALL: there are no calls in progress
  * - IN_PROGRESS: at least one call is in progress
  */
 enum CallState {
   NO_CALL,
   IN_PROGRESS
 };
@@ -82,32 +92,32 @@ enum CallHeldState {
 typedef struct {
   const char* name;
   const char* range;
   int value;
 } CINDItem;
 
 enum CINDType {
   BATTCHG = 1,
-  SIGNAL,
+  CALL,
+  CALLHELD,
+  CALLSETUP,
   SERVICE,
-  CALL,
-  CALLSETUP,
-  CALLHELD,
-  ROAM,
+  SIGNAL,
+  ROAM
 };
 
 static CINDItem sCINDItems[] = {
   {},
   {"battchg", "0-5", 5},
-  {"signal", "0-5", 5},
-  {"service", "0,1", 1},
   {"call", "0,1", CallState::NO_CALL},
+  {"callheld", "0-2", CallHeldState::NO_CALLHELD},
   {"callsetup", "0-3", CallSetupState::NO_CALLSETUP},
-  {"callheld", "0-2", CallHeldState::NO_CALLHELD},
+  {"service", "0,1", 0},
+  {"signal", "0-5", 0},
   {"roam", "0,1", 0}
 };
 
 class mozilla::dom::bluetooth::BluetoothHfpManagerObserver : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
@@ -130,26 +140,32 @@ public:
       return false;
     }
 
     if (NS_FAILED(obs->AddObserver(this, MOBILE_CONNECTION_ICCINFO_CHANGED, false))) {
       NS_WARNING("Failed to add mobile connection iccinfo change observer!");
       return false;
     }
 
+    if (NS_FAILED(obs->AddObserver(this, MOBILE_CONNECTION_VOICE_CHANGED, false))) {
+      NS_WARNING("Failed to add mobile connection voice change observer!");
+      return false;
+    }
+
     return true;
   }
 
   bool Shutdown()
   {
     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     if (!obs ||
         NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
         NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID)) ||
-        NS_FAILED(obs->RemoveObserver(this, MOBILE_CONNECTION_ICCINFO_CHANGED))) {
+        NS_FAILED(obs->RemoveObserver(this, MOBILE_CONNECTION_ICCINFO_CHANGED)) ||
+        NS_FAILED(obs->RemoveObserver(this, MOBILE_CONNECTION_VOICE_CHANGED))) {
       NS_WARNING("Can't unregister observers, or already unregistered!");
       return false;
     }
     return true;
   }
 
   ~BluetoothHfpManagerObserver()
   {
@@ -186,46 +202,39 @@ public:
   {
     NS_WARNING("Unable to get value for '" AUDIO_VOLUME_BT_SCO "'");
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS1(GetVolumeTask, nsISettingsServiceCallback);
 
-namespace {
-  StaticRefPtr<BluetoothHfpManager> gBluetoothHfpManager;
-  StaticRefPtr<BluetoothHfpManagerObserver> sHfpObserver;
-  bool gInShutdown = false;
-  static bool sStopSendingRingFlag = true;
-
-  static int sRingInterval = 3000; //unit: ms
-} // anonymous namespace
-
-NS_IMPL_ISUPPORTS1(BluetoothHfpManagerObserver, nsIObserver)
-
 NS_IMETHODIMP
 BluetoothHfpManagerObserver::Observe(nsISupports* aSubject,
                                      const char* aTopic,
                                      const PRUnichar* aData)
 {
   MOZ_ASSERT(gBluetoothHfpManager);
 
   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
     return gBluetoothHfpManager->HandleVolumeChanged(nsDependentString(aData));
   } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     return gBluetoothHfpManager->HandleShutdown();
   } else if (!strcmp(aTopic, MOBILE_CONNECTION_ICCINFO_CHANGED)) {
     return gBluetoothHfpManager->HandleIccInfoChanged();
+  } else if (!strcmp(aTopic, MOBILE_CONNECTION_VOICE_CHANGED)) {
+    return gBluetoothHfpManager->HandleVoiceConnectionChanged();
   }
 
   MOZ_ASSERT(false, "BluetoothHfpManager got unexpected topic!");
   return NS_ERROR_UNEXPECTED;
 }
 
+NS_IMPL_ISUPPORTS1(BluetoothHfpManagerObserver, nsIObserver)
+
 class SendRingIndicatorTask : public Task
 {
 public:
   SendRingIndicatorTask(const char* aNumber, int aType = TOA_UNKNOWN)
     : mNumber(aNumber)
     , mType(aType)
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -498,16 +507,62 @@ BluetoothHfpManager::HandleVolumeChanged
   if (GetConnectionStatus() == SocketConnectionStatus::SOCKET_CONNECTED) {
     SendCommand("+VGS: ", mCurrentVgs);
   }
 
   return NS_OK;
 }
 
 nsresult
+BluetoothHfpManager::HandleVoiceConnectionChanged()
+{
+  nsCOMPtr<nsIMobileConnectionProvider> connection =
+    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
+
+  nsIDOMMozMobileConnectionInfo* voiceInfo;
+  connection->GetVoiceConnectionInfo(&voiceInfo);
+  NS_ENSURE_TRUE(voiceInfo, NS_ERROR_FAILURE);
+
+  bool roaming;
+  voiceInfo->GetRoaming(&roaming);
+  if (roaming != sCINDItems[CINDType::ROAM].value) {
+    sCINDItems[CINDType::ROAM].value = roaming;
+    SendCommand("+CIEV: ", CINDType::ROAM);
+  }
+
+  bool service = false;
+  nsString regState;
+  voiceInfo->GetState(regState);
+  if (regState.EqualsLiteral("registered")) {
+    service = true;
+  }
+  if (service != sCINDItems[CINDType::SERVICE].value) {
+    sCINDItems[CINDType::SERVICE].value = service;
+    SendCommand("+CIEV: ", CINDType::SERVICE);
+  }
+
+  uint8_t signal;
+  JS::Value value;
+  voiceInfo->GetRelSignalStrength(&value);
+  if (!value.isNumber()) {
+    NS_WARNING("Failed to get relSignalStrength in BluetoothHfpManager");
+    return NS_ERROR_FAILURE;
+  }
+  signal = ceil(value.toNumber() / 20.0);
+
+  if (signal != sCINDItems[CINDType::SIGNAL].value) {
+    sCINDItems[CINDType::SIGNAL].value = signal;
+    SendCommand("+CIEV: ", CINDType::SIGNAL);
+  }
+
+  return NS_OK;
+}
+
+nsresult
 BluetoothHfpManager::HandleIccInfoChanged()
 {
   nsCOMPtr<nsIMobileConnectionProvider> connection =
     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
 
   nsIDOMMozMobileICCInfo* iccInfo;
   connection->GetIccInfo(&iccInfo);
@@ -790,39 +845,33 @@ BluetoothHfpManager::SendLine(const char
   msg += kHfpCrlf;
 
   return SendSocketData(msg);
 }
 
 bool
 BluetoothHfpManager::SendCommand(const char* aCommand, const int aValue)
 {
+  if (mSocketStatus != SocketConnectionStatus::SOCKET_CONNECTED) {
+    return false;
+  }
+
   nsAutoCString message;
   int value = aValue;
   message += aCommand;
 
   if (!strcmp(aCommand, "+CIEV: ")) {
+    if ((aValue < 1) || (aValue > ArrayLength(sCINDItems) - 1)) {
+      NS_WARNING("unexpected CINDType for CIEV command");
+      return false;
+    }
+
     message.AppendInt(aValue);
     message += ",";
-    switch (aValue) {
-      case CINDType::CALL:
-        message.AppendInt(sCINDItems[CINDType::CALL].value);
-        break;
-      case CINDType::CALLSETUP:
-        message.AppendInt(sCINDItems[CINDType::CALLSETUP].value);
-        break;
-      case CINDType::CALLHELD:
-        message.AppendInt(sCINDItems[CINDType::CALLHELD].value);
-        break;
-      default:
-#ifdef DEBUG
-        NS_WARNING("unexpected CINDType for CIEV command");
-#endif
-        return false;
-    }
+    message.AppendInt(sCINDItems[aValue].value);
   } else if (!strcmp(aCommand, "+CIND: ")) {
     if (!aValue) {
       for (uint8_t i = 1; i < ArrayLength(sCINDItems); i++) {
         message += "(\"";
         message += sCINDItems[i].name;
         message += "\",(";
         message += sCINDItems[i].range;
         message += ")";
@@ -1052,17 +1101,17 @@ BluetoothHfpManager::OnConnectSuccess()
   }
 
   // Cache device path for NotifySettings() since we can't get socket address
   // when a headset disconnect with us
   GetSocketAddr(mDevicePath);
   mSocketStatus = GetConnectionStatus();
 
   nsCOMPtr<nsIRILContentHelper> ril =
-    do_GetService("@mozilla.org/ril/content-helper;1");
+    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   NS_ENSURE_TRUE_VOID(ril);
   ril->EnumerateCalls(mListener->GetCallback());
 
   NotifySettings();
 }
 
 void
 BluetoothHfpManager::OnConnectError()
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -37,19 +37,20 @@ public:
   void SetupCIND(int aCallIndex, int aCallState,
                  const char* aPhoneNumber, bool aInitial);
   bool Listen();
   void SetVolume(int aVolume);
 
 private:
   friend class BluetoothHfpManagerObserver;
   BluetoothHfpManager();
-  nsresult HandleVolumeChanged(const nsAString& aData);
+  nsresult HandleIccInfoChanged();
   nsresult HandleShutdown();
-  nsresult HandleIccInfoChanged();
+  nsresult HandleVolumeChanged(const nsAString& aData);
+  nsresult HandleVoiceConnectionChanged();
 
   bool Init();
   void Cleanup();
   void NotifyDialer(const nsAString& aCommand);
   void NotifySettings();
   virtual void OnConnectSuccess() MOZ_OVERRIDE;
   virtual void OnConnectError() MOZ_OVERRIDE;
   virtual void OnDisconnect() MOZ_OVERRIDE;