Bug 1053804: Add Bluetooth Handsfree notifications, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Thu, 21 Aug 2014 10:10:37 +0200
changeset 215124 adc4a9593007a5069459b766c03475a9a07d420e
parent 215123 56bc65672f3a0fbfd7c5a32605e4da3c455a527c
child 215125 edfc55422f6f08bc1572814b997ed8f2bf05cbb7
push idunknown
push userunknown
push dateunknown
reviewersshuang
bugs1053804
milestone34.0a1
Bug 1053804: Add Bluetooth Handsfree notifications, r=shuang The notification interface consists of virtual methods that are invoked form the Bluetooth backend on certain events. The Handsfree manager can implement the methods to handle these events.
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/bluedroid/BluetoothInterface.cpp
dom/bluetooth/bluedroid/BluetoothInterface.h
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -241,26 +241,40 @@ enum BluetoothSocketType {
   EL2CAP = 4
 };
 
 enum BluetoothHandsfreeAtResponse {
   HFP_AT_RESPONSE_ERROR,
   HFP_AT_RESPONSE_OK
 };
 
+enum BluetoothHandsfreeAudioState {
+  HFP_AUDIO_STATE_DISCONNECTED,
+  HFP_AUDIO_STATE_CONNECTING,
+  HFP_AUDIO_STATE_CONNECTED,
+  HFP_AUDIO_STATE_DISCONNECTING,
+};
+
 enum BluetoothHandsfreeCallAddressType {
   HFP_CALL_ADDRESS_TYPE_UNKNOWN,
   HFP_CALL_ADDRESS_TYPE_INTERNATIONAL
 };
 
 enum BluetoothHandsfreeCallDirection {
   HFP_CALL_DIRECTION_OUTGOING,
   HFP_CALL_DIRECTION_INCOMING
 };
 
+enum BluetoothHandsfreeCallHoldType {
+  HFP_CALL_HOLD_RELEASEHELD,
+  HFP_CALL_HOLD_RELEASEACTIVE_ACCEPTHELD,
+  HFP_CALL_HOLD_HOLDACTIVE_ACCEPTHELD,
+  HFP_CALL_HOLD_ADDHELDTOCONF
+};
+
 enum BluetoothHandsfreeCallMode {
   HFP_CALL_MODE_VOICE,
   HFP_CALL_MODE_DATA,
   HFP_CALL_MODE_FAX
 };
 
 enum BluetoothHandsfreeCallMptyType {
   HFP_CALL_MPTY_TYPE_SINGLE,
@@ -272,26 +286,45 @@ enum BluetoothHandsfreeCallState {
   HFP_CALL_STATE_HELD,
   HFP_CALL_STATE_DIALING,
   HFP_CALL_STATE_ALERTING,
   HFP_CALL_STATE_INCOMING,
   HFP_CALL_STATE_WAITING,
   HFP_CALL_STATE_IDLE
 };
 
+enum BluetoothHandsfreeConnectionState
+{
+  HFP_CONNECTION_STATE_DISCONNECTED,
+  HFP_CONNECTION_STATE_CONNECTING,
+  HFP_CONNECTION_STATE_CONNECTED,
+  HFP_CONNECTION_STATE_SLC_CONNECTED,
+  HFP_CONNECTION_STATE_DISCONNECTING
+};
+
 enum BluetoothHandsfreeNetworkState {
   HFP_NETWORK_STATE_NOT_AVAILABLE,
   HFP_NETWORK_STATE_AVAILABLE
 };
 
+enum BluetoothHandsfreeNRECState {
+  HFP_NREC_STOPPED,
+  HFP_NREC_STARTED
+};
+
 enum BluetoothHandsfreeServiceType {
   HFP_SERVICE_TYPE_HOME,
   HFP_SERVICE_TYPE_ROAMING
 };
 
+enum BluetoothHandsfreeVoiceRecognitionState {
+  HFP_VOICE_RECOGNITION_STOPPED,
+  HFP_VOICE_RECOGNITION_STARTED
+};
+
 enum BluetoothHandsfreeVolumeType {
   HFP_VOLUME_TYPE_SPEAKER,
   HFP_VOLUME_TYPE_MICROPHONE
 };
 
 class BluetoothSignal;
 typedef mozilla::Observer<BluetoothSignal> BluetoothSignalObserver;
 
--- a/dom/bluetooth/bluedroid/BluetoothInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.cpp
@@ -355,21 +355,35 @@ Convert(bt_discovery_state_t aIn, bool& 
   if (aIn >= MOZ_ARRAY_LENGTH(sDiscoveryState)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sDiscoveryState[aIn];
   return NS_OK;
 }
 
 static nsresult
+Convert(const char* aIn, nsACString& aOut)
+{
+  aOut.Assign(aIn);
+
+  return NS_OK;
+}
+
+static nsresult
+Convert(const char* aIn, nsAString& aOut)
+{
+  aOut = NS_ConvertUTF8toUTF16(aIn);
+
+  return NS_OK;
+}
+
+static nsresult
 Convert(const bt_bdname_t& aIn, nsAString& aOut)
 {
-  aOut = NS_ConvertUTF8toUTF16(reinterpret_cast<const char*>(aIn.name));
-
-  return NS_OK;
+  return Convert(reinterpret_cast<const char*>(aIn.name), aOut);
 }
 
 static nsresult
 Convert(const bt_bdname_t* aIn, nsAString& aOut)
 {
   if (!aIn) {
     aOut.Truncate();
     return NS_OK;
@@ -599,16 +613,113 @@ Convert(BluetoothHandsfreeVolumeType aIn
   };
   if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sVolumeType[aIn];
   return NS_OK;
 }
 
+static nsresult
+Convert(bthf_audio_state_t aIn, BluetoothHandsfreeAudioState& aOut)
+{
+  static const BluetoothHandsfreeAudioState sAudioState[] = {
+    CONVERT(BTHF_AUDIO_STATE_DISCONNECTED, HFP_AUDIO_STATE_DISCONNECTED),
+    CONVERT(BTHF_AUDIO_STATE_CONNECTING, HFP_AUDIO_STATE_CONNECTING),
+    CONVERT(BTHF_AUDIO_STATE_CONNECTED, HFP_AUDIO_STATE_CONNECTED),
+    CONVERT(BTHF_AUDIO_STATE_DISCONNECTING, HFP_AUDIO_STATE_DISCONNECTING)
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sAudioState)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAudioState[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(bthf_chld_type_t aIn, BluetoothHandsfreeCallHoldType& aOut)
+{
+  static const BluetoothHandsfreeCallHoldType sCallHoldType[] = {
+    CONVERT(BTHF_CHLD_TYPE_RELEASEHELD, HFP_CALL_HOLD_RELEASEHELD),
+    CONVERT(BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD,
+      HFP_CALL_HOLD_RELEASEACTIVE_ACCEPTHELD),
+    CONVERT(BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD,
+      HFP_CALL_HOLD_HOLDACTIVE_ACCEPTHELD),
+    CONVERT(BTHF_CHLD_TYPE_ADDHELDTOCONF, HFP_CALL_HOLD_ADDHELDTOCONF)
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sCallHoldType)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sCallHoldType[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(bthf_connection_state_t aIn, BluetoothHandsfreeConnectionState& aOut)
+{
+  static const BluetoothHandsfreeConnectionState sConnectionState[] = {
+    CONVERT(BTHF_CONNECTION_STATE_DISCONNECTED,
+      HFP_CONNECTION_STATE_DISCONNECTED),
+    CONVERT(BTHF_CONNECTION_STATE_CONNECTING, HFP_CONNECTION_STATE_CONNECTING),
+    CONVERT(BTHF_CONNECTION_STATE_CONNECTED, HFP_CONNECTION_STATE_CONNECTED),
+    CONVERT(BTHF_CONNECTION_STATE_SLC_CONNECTED,
+      HFP_CONNECTION_STATE_SLC_CONNECTED),
+    CONVERT(BTHF_CONNECTION_STATE_DISCONNECTING,
+      HFP_CONNECTION_STATE_DISCONNECTING)
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sConnectionState)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sConnectionState[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(bthf_nrec_t aIn, BluetoothHandsfreeNRECState& aOut)
+{
+  static const BluetoothHandsfreeNRECState sNRECState[] = {
+    CONVERT(BTHF_NREC_STOP, HFP_NREC_STOPPED),
+    CONVERT(BTHF_NREC_START, HFP_NREC_STARTED)
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sNRECState)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sNRECState[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(bthf_vr_state_t aIn, BluetoothHandsfreeVoiceRecognitionState& aOut)
+{
+  static const BluetoothHandsfreeVoiceRecognitionState
+    sVoiceRecognitionState[] = {
+    CONVERT(BTHF_VR_STATE_STOPPED, HFP_VOICE_RECOGNITION_STOPPED),
+    CONVERT(BTHF_VR_STATE_STARTED, HFP_VOICE_RECOGNITION_STARTED)
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sVoiceRecognitionState)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sVoiceRecognitionState[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(bthf_volume_type_t aIn, BluetoothHandsfreeVolumeType& aOut)
+{
+  static const BluetoothHandsfreeVolumeType sVolumeType[] = {
+    CONVERT(BTHF_VOLUME_TYPE_SPK, HFP_VOLUME_TYPE_SPEAKER),
+    CONVERT(BTHF_VOLUME_TYPE_MIC, HFP_VOLUME_TYPE_MICROPHONE)
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sVolumeType[aIn];
+  return NS_OK;
+}
+
 #if ANDROID_VERSION >= 18
 static nsresult
 Convert(ControlPlayStatus aIn, btrc_play_status_t& aOut)
 {
   static const btrc_play_status_t sPlayStatus[] = {
     CONVERT(PLAYSTATUS_STOPPED, BTRC_PLAYSTATE_STOPPED),
     CONVERT(PLAYSTATUS_PLAYING, BTRC_PLAYSTATE_PLAYING),
     CONVERT(PLAYSTATUS_PAUSED, BTRC_PLAYSTATE_PAUSED),
@@ -951,16 +1062,70 @@ private:
   Tin2 mArg2;
   Tin3 mArg3;
 };
 
 //
 // Notification handling
 //
 
+template <typename ObjectWrapper, typename Res>
+class BluetoothNotificationRunnable0 : public nsRunnable
+{
+public:
+  typedef typename ObjectWrapper::ObjectType  ObjectType;
+  typedef BluetoothNotificationRunnable0<ObjectWrapper, Res> SelfType;
+
+  static already_AddRefed<SelfType> Create(Res (ObjectType::*aMethod)())
+  {
+    nsRefPtr<SelfType> runnable(new SelfType(aMethod));
+
+    return runnable.forget();
+  }
+
+  static void
+  Dispatch(Res (ObjectType::*aMethod)())
+  {
+    nsRefPtr<SelfType> runnable = Create(aMethod);
+
+    if (!runnable) {
+      BT_WARNING("BluetoothNotificationRunnable0::Create failed");
+      return;
+    }
+    nsresult rv = NS_DispatchToMainThread(runnable);
+    if (NS_FAILED(rv)) {
+      BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
+    }
+  }
+
+  NS_METHOD
+  Run() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    ObjectType* obj = ObjectWrapper::GetInstance();
+
+    if (!obj) {
+      BT_WARNING("Notification handler not initialized");
+    } else {
+      ((*obj).*mMethod)();
+    }
+    return NS_OK;
+  }
+
+private:
+  BluetoothNotificationRunnable0(Res (ObjectType::*aMethod)())
+  : mMethod(aMethod)
+  {
+    MOZ_ASSERT(mMethod);
+  }
+
+  Res (ObjectType::*mMethod)();
+};
+
 template <typename ObjectWrapper, typename Res,
           typename Tin1, typename Arg1=Tin1>
 class BluetoothNotificationRunnable1 : public nsRunnable
 {
 public:
   typedef typename ObjectWrapper::ObjectType  ObjectType;
   typedef BluetoothNotificationRunnable1<ObjectWrapper, Res,
                                          Tin1, Arg1> SelfType;
@@ -1917,16 +2082,241 @@ DispatchBluetoothHandsfreeResult(
   }
   nsresult rv = NS_DispatchToMainThread(runnable);
   if (NS_FAILED(rv)) {
     BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
   }
   return rv;
 }
 
+// Notification handling
+//
+
+BluetoothHandsfreeNotificationHandler::
+  ~BluetoothHandsfreeNotificationHandler()
+{ }
+
+static BluetoothHandsfreeNotificationHandler* sHandsfreeNotificationHandler;
+
+struct BluetoothHandsfreeCallback
+{
+  class HandsfreeNotificationHandlerWrapper
+  {
+  public:
+    typedef BluetoothHandsfreeNotificationHandler ObjectType;
+
+    static ObjectType* GetInstance()
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+
+      return sHandsfreeNotificationHandler;
+    }
+  };
+
+  // Notifications
+
+  typedef BluetoothNotificationRunnable2<HandsfreeNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothHandsfreeConnectionState,
+                                         nsString,
+                                         BluetoothHandsfreeConnectionState,
+                                         const nsAString&>
+    ConnectionStateNotification;
+
+  typedef BluetoothNotificationRunnable2<HandsfreeNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothHandsfreeAudioState,
+                                         nsString,
+                                         BluetoothHandsfreeAudioState,
+                                         const nsAString&>
+    AudioStateNotification;
+
+  typedef BluetoothNotificationRunnable1<HandsfreeNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothHandsfreeVoiceRecognitionState>
+    VoiceRecognitionNotification;
+
+  typedef BluetoothNotificationRunnable0<HandsfreeNotificationHandlerWrapper,
+                                         void>
+    AnswerCallNotification;
+
+  typedef BluetoothNotificationRunnable0<HandsfreeNotificationHandlerWrapper,
+                                         void>
+    HangupCallNotification;
+
+  typedef BluetoothNotificationRunnable2<HandsfreeNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothHandsfreeVolumeType, int>
+    VolumeNotification;
+
+  typedef BluetoothNotificationRunnable1<HandsfreeNotificationHandlerWrapper,
+                                         void, nsString, const nsAString&>
+    DialCallNotification;
+
+  typedef BluetoothNotificationRunnable1<HandsfreeNotificationHandlerWrapper,
+                                         void, char>
+    DtmfNotification;
+
+  typedef BluetoothNotificationRunnable1<HandsfreeNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothHandsfreeNRECState>
+    NRECNotification;
+
+  typedef BluetoothNotificationRunnable1<HandsfreeNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothHandsfreeCallHoldType>
+    CallHoldNotification;
+
+  typedef BluetoothNotificationRunnable0<HandsfreeNotificationHandlerWrapper,
+                                         void>
+    CnumNotification;
+
+  typedef BluetoothNotificationRunnable0<HandsfreeNotificationHandlerWrapper,
+                                         void>
+    CindNotification;
+
+  typedef BluetoothNotificationRunnable0<HandsfreeNotificationHandlerWrapper,
+                                         void>
+    CopsNotification;
+
+  typedef BluetoothNotificationRunnable0<HandsfreeNotificationHandlerWrapper,
+                                         void>
+    ClccNotification;
+
+  typedef BluetoothNotificationRunnable1<HandsfreeNotificationHandlerWrapper,
+                                         void, nsCString, const nsACString&>
+    UnknownAtNotification;
+
+  typedef BluetoothNotificationRunnable0<HandsfreeNotificationHandlerWrapper,
+                                         void>
+    KeyPressedNotification;
+
+  // Bluedroid Handsfree callbacks
+
+  static void
+  ConnectionState(bthf_connection_state_t aState, bt_bdaddr_t* aBdAddr)
+  {
+    ConnectionStateNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::ConnectionStateNotification,
+      aState, aBdAddr);
+  }
+
+  static void
+  AudioState(bthf_audio_state_t aState, bt_bdaddr_t* aBdAddr)
+  {
+    AudioStateNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::AudioStateNotification,
+      aState, aBdAddr);
+  }
+
+  static void
+  VoiceRecognition(bthf_vr_state_t aState)
+  {
+    VoiceRecognitionNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::VoiceRecognitionNotification,
+      aState);
+  }
+
+  static void
+  AnswerCall()
+  {
+    AnswerCallNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::AnswerCallNotification);
+  }
+
+  static void
+  HangupCall()
+  {
+    HangupCallNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::HangupCallNotification);
+  }
+
+  static void
+  Volume(bthf_volume_type_t aType, int aVolume)
+  {
+    VolumeNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::VolumeNotification,
+      aType, aVolume);
+  }
+
+  static void
+  DialCall(char* aNumber)
+  {
+    DialCallNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::DialCallNotification, aNumber);
+  }
+
+  static void
+  Dtmf(char aDtmf)
+  {
+    DtmfNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::DtmfNotification, aDtmf);
+  }
+
+  static void
+  NoiseReductionEchoCancellation(bthf_nrec_t aNrec)
+  {
+    NRECNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::NRECNotification, aNrec);
+  }
+
+  static void
+  CallHold(bthf_chld_type_t aChld)
+  {
+    CallHoldNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CallHoldNotification, aChld);
+  }
+
+  static void
+  Cnum()
+  {
+    CnumNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CnumNotification);
+  }
+
+  static void
+  Cind()
+  {
+    CindNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CindNotification);
+  }
+
+  static void
+  Cops()
+  {
+    CopsNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CopsNotification);
+  }
+
+  static void
+  Clcc()
+  {
+    ClccNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::ClccNotification);
+  }
+
+  static void
+  UnknownAt(char* aAtString)
+  {
+    UnknownAtNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::UnknownAtNotification,
+      aAtString);
+  }
+
+  static void
+  KeyPressedCallback()
+  {
+    KeyPressedNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::KeyPressedNotification);
+  }
+};
+
+// Interface
+//
+
 BluetoothHandsfreeInterface::BluetoothHandsfreeInterface(
   const bthf_interface_t* aInterface)
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothHandsfreeInterface::~BluetoothHandsfreeInterface()
--- a/dom/bluetooth/bluedroid/BluetoothInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.h
@@ -72,16 +72,92 @@ protected:
 private:
   const btsock_interface_t* mInterface;
 };
 
 //
 // Handsfree Interface
 //
 
+class BluetoothHandsfreeNotificationHandler
+{
+public:
+  virtual ~BluetoothHandsfreeNotificationHandler();
+
+  virtual void
+  ConnectionStateNotification(BluetoothHandsfreeConnectionState aState,
+                              const nsAString& aBdAddr)
+  { }
+
+  virtual void
+  AudioStateNotification(BluetoothHandsfreeAudioState aState,
+                         const nsAString& aBdAddr)
+  { }
+
+  virtual void
+  VoiceRecognitionNotification(BluetoothHandsfreeVoiceRecognitionState aState)
+  { }
+
+  virtual void
+  AnswerCallNotification()
+  { }
+
+  virtual void
+  HangupCallNotification()
+  { }
+
+  virtual void
+  VolumeNotification(BluetoothHandsfreeVolumeType aType, int aVolume)
+  { }
+
+  virtual void
+  DialCallNotification(const nsAString& aNumber)
+  { }
+
+  virtual void
+  DtmfNotification(char aDtmf)
+  { }
+
+  virtual void
+  NRECNotification(BluetoothHandsfreeNRECState aNrec)
+  { }
+
+  virtual void
+  CallHoldNotification(BluetoothHandsfreeCallHoldType aChld)
+  { }
+
+  virtual void
+  CnumNotification()
+  { }
+
+  virtual void
+  CindNotification()
+  { }
+
+  virtual void
+  CopsNotification()
+  { }
+
+  virtual void
+  ClccNotification()
+  { }
+
+  virtual void
+  UnknownAtNotification(const nsACString& aAtString)
+  { }
+
+  virtual void
+  KeyPressedNotification()
+  { }
+
+protected:
+  BluetoothHandsfreeNotificationHandler()
+  { }
+};
+
 class BluetoothHandsfreeResultHandler
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothHandsfreeResultHandler)
 
   virtual ~BluetoothHandsfreeResultHandler() { }
 
   virtual void OnError(BluetoothStatus aStatus)