dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "base/basictypes.h"
     9 #include "BluetoothHfpManager.h"
    10 #include "BluetoothProfileController.h"
    11 #include "BluetoothUtils.h"
    13 #include "jsapi.h"
    14 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
    15 #include "mozilla/Services.h"
    16 #include "mozilla/StaticPtr.h"
    17 #include "nsContentUtils.h"
    18 #include "nsIAudioManager.h"
    19 #include "nsIDOMIccInfo.h"
    20 #include "nsIDOMMobileConnection.h"
    21 #include "nsIIccProvider.h"
    22 #include "nsIMobileConnectionProvider.h"
    23 #include "nsIObserverService.h"
    24 #include "nsISettingsService.h"
    25 #include "nsITelephonyProvider.h"
    26 #include "nsRadioInterfaceLayer.h"
    27 #include "nsServiceManagerUtils.h"
    28 #include "nsThreadUtils.h"
    30 #define MOZSETTINGS_CHANGED_ID               "mozsettings-changed"
    31 #define AUDIO_VOLUME_BT_SCO_ID               "audio.volume.bt_sco"
    33 /**
    34  * Dispatch task with arguments to main thread.
    35  */
    36 #define BT_HF_DISPATCH_MAIN(args...) \
    37   NS_DispatchToMainThread(new MainThreadTask(args))
    39 /**
    40  * Process bluedroid callbacks with corresponding handlers.
    41  */
    42 #define BT_HF_PROCESS_CB(func, args...)          \
    43   do {                                           \
    44     NS_ENSURE_TRUE_VOID(sBluetoothHfpManager);   \
    45     sBluetoothHfpManager->func(args);            \
    46   } while(0)
    48 using namespace mozilla;
    49 using namespace mozilla::ipc;
    50 USING_BLUETOOTH_NAMESPACE
    52 namespace {
    53   StaticRefPtr<BluetoothHfpManager> sBluetoothHfpManager;
    54   static const bthf_interface_t* sBluetoothHfpInterface = nullptr;
    56   bool sInShutdown = false;
    58   // Wait for 2 seconds for Dialer processing event 'BLDN'. '2' seconds is a
    59   // magic number. The mechanism should be revised once we can get call history.
    60   static int sWaitingForDialingInterval = 2000; //unit: ms
    62   // Wait 3.7 seconds until Dialer stops playing busy tone. '3' seconds is the
    63   // time window set in Dialer and the extra '0.7' second is a magic number.
    64   // The mechanism should be revised once we know the exact time at which
    65   // Dialer stops playing.
    66   static int sBusyToneInterval = 3700; //unit: ms
    67 } // anonymous namespace
    69 // Main thread task commands
    70 enum MainThreadTaskCmd {
    71   NOTIFY_CONN_STATE_CHANGED,
    72   NOTIFY_DIALER,
    73   NOTIFY_SCO_VOLUME_CHANGED,
    74   POST_TASK_RESPOND_TO_BLDN,
    75   POST_TASK_CLOSE_SCO
    76 };
    78 static void
    79 ConnectionStateCallback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr)
    80 {
    81   BT_HF_PROCESS_CB(ProcessConnectionState, state, bd_addr);
    82 }
    84 static void
    85 AudioStateCallback(bthf_audio_state_t state, bt_bdaddr_t* bd_addr)
    86 {
    87   BT_HF_PROCESS_CB(ProcessAudioState, state, bd_addr);
    88 }
    90 static void
    91 VoiceRecognitionCallback(bthf_vr_state_t state)
    92 {
    93   // No support
    94 }
    96 static void
    97 AnswerCallCallback()
    98 {
    99   BT_HF_PROCESS_CB(ProcessAnswerCall);
   100 }
   102 static void
   103 HangupCallCallback()
   104 {
   105   BT_HF_PROCESS_CB(ProcessHangupCall);
   106 }
   108 static void
   109 VolumeControlCallback(bthf_volume_type_t type, int volume)
   110 {
   111   BT_HF_PROCESS_CB(ProcessVolumeControl, type, volume);
   112 }
   114 static void
   115 DialCallCallback(char *number)
   116 {
   117   BT_HF_PROCESS_CB(ProcessDialCall, number);
   118 }
   120 static void
   121 DtmfCmdCallback(char dtmf)
   122 {
   123   BT_HF_PROCESS_CB(ProcessDtmfCmd, dtmf);
   124 }
   126 static void
   127 NoiceReductionCallback(bthf_nrec_t nrec)
   128 {
   129   // No support
   130 }
   132 static void
   133 AtChldCallback(bthf_chld_type_t chld)
   134 {
   135   BT_HF_PROCESS_CB(ProcessAtChld, chld);
   136 }
   138 static void
   139 AtCnumCallback()
   140 {
   141   BT_HF_PROCESS_CB(ProcessAtCnum);
   142 }
   144 static void
   145 AtCindCallback()
   146 {
   147   BT_HF_PROCESS_CB(ProcessAtCind);
   148 }
   150 static void
   151 AtCopsCallback()
   152 {
   153   BT_HF_PROCESS_CB(ProcessAtCops);
   154 }
   156 static void
   157 AtClccCallback()
   158 {
   159   BT_HF_PROCESS_CB(ProcessAtClcc);
   160 }
   162 static void
   163 UnknownAtCallback(char *at_string)
   164 {
   165   BT_HF_PROCESS_CB(ProcessUnknownAt, at_string);
   166 }
   168 static void
   169 KeyPressedCallback()
   170 {
   171   BT_HF_PROCESS_CB(ProcessKeyPressed);
   172 }
   174 static bthf_callbacks_t sBluetoothHfpCallbacks = {
   175   sizeof(sBluetoothHfpCallbacks),
   176   ConnectionStateCallback,
   177   AudioStateCallback,
   178   VoiceRecognitionCallback,
   179   AnswerCallCallback,
   180   HangupCallCallback,
   181   VolumeControlCallback,
   182   DialCallCallback,
   183   DtmfCmdCallback,
   184   NoiceReductionCallback,
   185   AtChldCallback,
   186   AtCnumCallback,
   187   AtCindCallback,
   188   AtCopsCallback,
   189   AtClccCallback,
   190   UnknownAtCallback,
   191   KeyPressedCallback
   192 };
   194 static bool
   195 IsValidDtmf(const char aChar) {
   196   // Valid DTMF: [*#0-9ABCD]
   197   return (aChar == '*' || aChar == '#') ||
   198          (aChar >= '0' && aChar <= '9') ||
   199          (aChar >= 'A' && aChar <= 'D');
   200 }
   202 class BluetoothHfpManager::GetVolumeTask : public nsISettingsServiceCallback
   203 {
   204 public:
   205   NS_DECL_ISUPPORTS
   207   NS_IMETHOD
   208   Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
   209   {
   210     MOZ_ASSERT(NS_IsMainThread());
   212     JSContext *cx = nsContentUtils::GetCurrentJSContext();
   213     NS_ENSURE_TRUE(cx, NS_OK);
   215     if (!aResult.isNumber()) {
   216       BT_WARNING("'" AUDIO_VOLUME_BT_SCO_ID "' is not a number!");
   217       return NS_OK;
   218     }
   220     BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
   221     hfp->mCurrentVgs = aResult.toNumber();
   223     return NS_OK;
   224   }
   226   NS_IMETHOD
   227   HandleError(const nsAString& aName)
   228   {
   229     BT_WARNING("Unable to get value for '" AUDIO_VOLUME_BT_SCO_ID "'");
   230     return NS_OK;
   231   }
   232 };
   234 class BluetoothHfpManager::CloseScoTask : public Task
   235 {
   236 private:
   237   void Run() MOZ_OVERRIDE
   238   {
   239     MOZ_ASSERT(sBluetoothHfpManager);
   240     sBluetoothHfpManager->DisconnectSco();
   241   }
   242 };
   244 class BluetoothHfpManager::RespondToBLDNTask : public Task
   245 {
   246 private:
   247   void Run() MOZ_OVERRIDE
   248   {
   249     MOZ_ASSERT(sBluetoothHfpManager);
   251     if (!sBluetoothHfpManager->mDialingRequestProcessed) {
   252       sBluetoothHfpManager->mDialingRequestProcessed = true;
   253       sBluetoothHfpManager->SendResponse(BTHF_AT_RESPONSE_ERROR);
   254     }
   255   }
   256 };
   258 class BluetoothHfpManager::MainThreadTask : public nsRunnable
   259 {
   260 public:
   261   MainThreadTask(const int aCommand,
   262                  const nsAString& aParameter = EmptyString())
   263     : mCommand(aCommand), mParameter(aParameter)
   264   {
   265   }
   267   nsresult Run()
   268   {
   269     MOZ_ASSERT(NS_IsMainThread());
   270     MOZ_ASSERT(sBluetoothHfpManager);
   272     switch (mCommand) {
   273       case MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED:
   274         sBluetoothHfpManager->NotifyConnectionStateChanged(mParameter);
   275         break;
   276       case MainThreadTaskCmd::NOTIFY_DIALER:
   277         sBluetoothHfpManager->NotifyDialer(mParameter);
   278         break;
   279       case MainThreadTaskCmd::NOTIFY_SCO_VOLUME_CHANGED:
   280         {
   281           nsCOMPtr<nsIObserverService> os =
   282             mozilla::services::GetObserverService();
   283           NS_ENSURE_TRUE(os, NS_OK);
   285           os->NotifyObservers(nullptr, "bluetooth-volume-change",
   286                               mParameter.get());
   287         }
   288         break;
   289       case MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN:
   290         MessageLoop::current()->
   291           PostDelayedTask(FROM_HERE, new RespondToBLDNTask(),
   292                           sWaitingForDialingInterval);
   293         break;
   294       case MainThreadTaskCmd::POST_TASK_CLOSE_SCO:
   295         MessageLoop::current()->
   296           PostDelayedTask(FROM_HERE, new CloseScoTask(),
   297                           sBusyToneInterval);
   298         break;
   299       default:
   300         BT_WARNING("MainThreadTask: Unknown command %d", mCommand);
   301         break;
   302     }
   304     return NS_OK;
   305   }
   307 private:
   308   int mCommand;
   309   nsString mParameter;
   310 };
   312 NS_IMPL_ISUPPORTS(BluetoothHfpManager::GetVolumeTask,
   313                   nsISettingsServiceCallback);
   315 /**
   316  *  Call
   317  */
   318 Call::Call()
   319 {
   320   Reset();
   321 }
   323 void
   324 Call::Set(const nsAString& aNumber, const bool aIsOutgoing)
   325 {
   326   mNumber = aNumber;
   327   mDirection = (aIsOutgoing) ? BTHF_CALL_DIRECTION_OUTGOING :
   328                                BTHF_CALL_DIRECTION_INCOMING;
   329   // Same logic as implementation in ril_worker.js
   330   if (aNumber.Length() && aNumber[0] == '+') {
   331     mType = BTHF_CALL_ADDRTYPE_INTERNATIONAL;
   332   }
   333 }
   335 void
   336 Call::Reset()
   337 {
   338   mState = nsITelephonyProvider::CALL_STATE_DISCONNECTED;
   339   mDirection = BTHF_CALL_DIRECTION_OUTGOING;
   340   mNumber.Truncate();
   341   mType = BTHF_CALL_ADDRTYPE_UNKNOWN;
   342 }
   344 bool
   345 Call::IsActive()
   346 {
   347   return (mState == nsITelephonyProvider::CALL_STATE_CONNECTED);
   348 }
   350 /**
   351  *  BluetoothHfpManager
   352  */
   353 BluetoothHfpManager::BluetoothHfpManager() : mPhoneType(PhoneType::NONE)
   354 {
   355   Reset();
   356 }
   358 void
   359 BluetoothHfpManager::ResetCallArray()
   360 {
   361   mCurrentCallArray.Clear();
   362   // Append a call object at the beginning of mCurrentCallArray since call
   363   // index from RIL starts at 1.
   364   Call call;
   365   mCurrentCallArray.AppendElement(call);
   367   if (mPhoneType == PhoneType::CDMA) {
   368     mCdmaSecondCall.Reset();
   369   }
   370 }
   372 void
   373 BluetoothHfpManager::Reset()
   374 {
   375   mReceiveVgsFlag = false;
   376   mDialingRequestProcessed = true;
   378   mConnectionState = BTHF_CONNECTION_STATE_DISCONNECTED;
   379   mPrevConnectionState = BTHF_CONNECTION_STATE_DISCONNECTED;
   380   mAudioState = BTHF_AUDIO_STATE_DISCONNECTED;
   382   // Phone & Device CIND
   383   ResetCallArray();
   384   mBattChg = 5;
   385   mService = 0;
   386   mRoam = 0;
   387   mSignal = 0;
   389   mController = nullptr;
   390 }
   392 bool
   393 BluetoothHfpManager::Init()
   394 {
   395   MOZ_ASSERT(NS_IsMainThread());
   397   NS_ENSURE_TRUE(InitHfpInterface(), false);
   399   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   400   NS_ENSURE_TRUE(obs, false);
   402   if (NS_FAILED(obs->AddObserver(this, MOZSETTINGS_CHANGED_ID, false)) ||
   403       NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
   404     BT_WARNING("Failed to add observers!");
   405     return false;
   406   }
   408   hal::RegisterBatteryObserver(this);
   410   mListener = new BluetoothRilListener();
   411   NS_ENSURE_TRUE(mListener->Listen(true), false);
   413   nsCOMPtr<nsISettingsService> settings =
   414     do_GetService("@mozilla.org/settingsService;1");
   415   NS_ENSURE_TRUE(settings, false);
   417   nsCOMPtr<nsISettingsServiceLock> settingsLock;
   418   nsresult rv = settings->CreateLock(nullptr, getter_AddRefs(settingsLock));
   419   NS_ENSURE_SUCCESS(rv, false);
   421   nsRefPtr<GetVolumeTask> callback = new GetVolumeTask();
   422   rv = settingsLock->Get(AUDIO_VOLUME_BT_SCO_ID, callback);
   423   NS_ENSURE_SUCCESS(rv, false);
   425   return true;
   426 }
   428 bool
   429 BluetoothHfpManager::InitHfpInterface()
   430 {
   431   const bt_interface_t* btInf = GetBluetoothInterface();
   432   NS_ENSURE_TRUE(btInf, false);
   434   if (sBluetoothHfpInterface) {
   435     sBluetoothHfpInterface->cleanup();
   436     sBluetoothHfpInterface = nullptr;
   437   }
   439   bthf_interface_t *interface = (bthf_interface_t *)
   440     btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID);
   441   NS_ENSURE_TRUE(interface, false);
   443   NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
   444     interface->init(&sBluetoothHfpCallbacks), false);
   445   sBluetoothHfpInterface = interface;
   447   return true;
   448 }
   450 BluetoothHfpManager::~BluetoothHfpManager()
   451 {
   452   if (!mListener->Listen(false)) {
   453     BT_WARNING("Failed to stop listening RIL");
   454   }
   455   mListener = nullptr;
   457   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   458   NS_ENSURE_TRUE_VOID(obs);
   460   if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
   461       NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID))) {
   462     BT_WARNING("Failed to remove observers!");
   463   }
   465   hal::UnregisterBatteryObserver(this);
   466   DeinitHfpInterface();
   467 }
   469 void
   470 BluetoothHfpManager::DeinitHfpInterface()
   471 {
   472   NS_ENSURE_TRUE_VOID(GetBluetoothInterface());
   474   if (sBluetoothHfpInterface) {
   475     sBluetoothHfpInterface->cleanup();
   476     sBluetoothHfpInterface = nullptr;
   477   }
   478 }
   480 //static
   481 BluetoothHfpManager*
   482 BluetoothHfpManager::Get()
   483 {
   484   MOZ_ASSERT(NS_IsMainThread());
   486   // If sBluetoothHfpManager already exists, exit early
   487   if (sBluetoothHfpManager) {
   488     return sBluetoothHfpManager;
   489   }
   491   // If we're in shutdown, don't create a new instance
   492   NS_ENSURE_FALSE(sInShutdown, nullptr);
   494   // Create a new instance, register, and return
   495   BluetoothHfpManager* manager = new BluetoothHfpManager();
   496   NS_ENSURE_TRUE(manager->Init(), nullptr);
   498   sBluetoothHfpManager = manager;
   499   return sBluetoothHfpManager;
   500 }
   502 NS_IMETHODIMP
   503 BluetoothHfpManager::Observe(nsISupports* aSubject,
   504                              const char* aTopic,
   505                              const char16_t* aData)
   506 {
   507   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
   508     HandleVolumeChanged(nsDependentString(aData));
   509   } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
   510     HandleShutdown();
   511   } else {
   512     MOZ_ASSERT(false, "BluetoothHfpManager got unexpected topic!");
   513     return NS_ERROR_UNEXPECTED;
   514   }
   516   return NS_OK;
   517 }
   519 void
   520 BluetoothHfpManager::Notify(const hal::BatteryInformation& aBatteryInfo)
   521 {
   522   // Range of battery level: [0, 1], double
   523   // Range of CIND::BATTCHG: [0, 5], int
   524   mBattChg = (int) ceil(aBatteryInfo.level() * 5.0);
   525   UpdateDeviceCIND();
   526 }
   528 void
   529 BluetoothHfpManager::ProcessConnectionState(bthf_connection_state_t aState,
   530                                             bt_bdaddr_t* aBdAddress)
   531 {
   532   BT_LOGR("state %d", aState);
   534   mPrevConnectionState = mConnectionState;
   535   mConnectionState = aState;
   537   if (aState == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
   538     BdAddressTypeToString(aBdAddress, mDeviceAddress);
   539     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED,
   540                         NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
   541   } else if (aState == BTHF_CONNECTION_STATE_DISCONNECTED) {
   542     DisconnectSco();
   543     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED,
   544                         NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
   545   }
   546 }
   548 void
   549 BluetoothHfpManager::ProcessAudioState(bthf_audio_state_t aState,
   550                                        bt_bdaddr_t* aBdAddress)
   551 {
   552   BT_LOGR("state %d", aState);
   554   mAudioState = aState;
   556   if (aState == BTHF_AUDIO_STATE_CONNECTED ||
   557       aState == BTHF_AUDIO_STATE_DISCONNECTED) {
   558     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED,
   559                         NS_LITERAL_STRING(BLUETOOTH_SCO_STATUS_CHANGED_ID));
   560   }
   561 }
   563 void
   564 BluetoothHfpManager::ProcessAnswerCall()
   565 {
   566   BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   567                       NS_LITERAL_STRING("ATA"));
   568 }
   570 void
   571 BluetoothHfpManager::ProcessHangupCall()
   572 {
   573   BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   574                       NS_LITERAL_STRING("CHUP"));
   575 }
   577 void
   578 BluetoothHfpManager::ProcessVolumeControl(bthf_volume_type_t aType,
   579                                           int aVolume)
   580 {
   581   NS_ENSURE_TRUE_VOID(aVolume >= 0 && aVolume <= 15);
   583   if (aType == BTHF_VOLUME_TYPE_MIC) {
   584     mCurrentVgm = aVolume;
   585   } else if (aType == BTHF_VOLUME_TYPE_SPK) {
   586     mReceiveVgsFlag = true;
   588     if (aVolume == mCurrentVgs) {
   589       // Keep current volume
   590       return;
   591     }
   593     nsString data;
   594     data.AppendInt(aVolume);
   595     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_SCO_VOLUME_CHANGED, data);
   596   }
   597 }
   599 void
   600 BluetoothHfpManager::ProcessDtmfCmd(char aDtmf)
   601 {
   602   NS_ENSURE_TRUE_VOID(IsValidDtmf(aDtmf));
   604   nsAutoCString message("VTS=");
   605   message += aDtmf;
   606   BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   607                       NS_ConvertUTF8toUTF16(message));
   608 }
   610 void
   611 BluetoothHfpManager::ProcessAtChld(bthf_chld_type_t aChld)
   612 {
   613   nsAutoCString message("CHLD=");
   614   message.AppendInt((int)aChld);
   615   BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   616                       NS_ConvertUTF8toUTF16(message));
   618   SendResponse(BTHF_AT_RESPONSE_OK);
   619 }
   621 void BluetoothHfpManager::ProcessDialCall(char *aNumber)
   622 {
   623   nsAutoCString message(aNumber);
   625   // There are three cases based on aNumber,
   626   // 1) Empty value:    Redial, BLDN
   627   // 2) >xxx:           Memory dial, ATD>xxx
   628   // 3) xxx:            Normal dial, ATDxxx
   629   // We need to respond OK/Error for dial requests for every case listed above,
   630   // 1) and 2):         Respond in either RespondToBLDNTask or
   631   //                    HandleCallStateChanged()
   632   // 3):                Respond here
   633   if (message.IsEmpty()) {
   634     mDialingRequestProcessed = false;
   635     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   636                         NS_LITERAL_STRING("BLDN"));
   637     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN);
   638   } else if (message[0] == '>') {
   639     mDialingRequestProcessed = false;
   640     nsAutoCString newMsg("ATD");
   641     newMsg += StringHead(message, message.Length() - 1);
   642     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   643                         NS_ConvertUTF8toUTF16(newMsg));
   644     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN);
   645   } else {
   646     nsAutoCString newMsg("ATD");
   647     newMsg += StringHead(message, message.Length() - 1);
   648     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   649                         NS_ConvertUTF8toUTF16(newMsg));
   650     SendResponse(BTHF_AT_RESPONSE_OK);
   651   }
   652 }
   654 void
   655 BluetoothHfpManager::ProcessAtCnum()
   656 {
   657   if (!mMsisdn.IsEmpty()) {
   658     nsAutoCString message("+CNUM: ,\"");
   659     message.Append(NS_ConvertUTF16toUTF8(mMsisdn).get());
   660     message.AppendLiteral("\",");
   661     message.AppendInt(BTHF_CALL_ADDRTYPE_UNKNOWN);
   662     message.AppendLiteral(",,4");
   664     SendLine(message.get());
   665   }
   667   SendResponse(BTHF_AT_RESPONSE_OK);
   668 }
   670 void
   671 BluetoothHfpManager::ProcessAtCind()
   672 {
   673   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
   675   int numActive = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_CONNECTED);
   676   int numHeld = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_HELD);
   678   bt_status_t status = sBluetoothHfpInterface->cind_response(
   679                           mService,
   680                           numActive,
   681                           numHeld,
   682                           ConvertToBthfCallState(GetCallSetupState()),
   683                           mSignal,
   684                           mRoam,
   685                           mBattChg);
   686   NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS);
   687 }
   689 void
   690 BluetoothHfpManager::ProcessAtCops()
   691 {
   692   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
   693   NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
   694     sBluetoothHfpInterface->cops_response(
   695       NS_ConvertUTF16toUTF8(mOperatorName).get()));
   696 }
   698 void
   699 BluetoothHfpManager::ProcessAtClcc()
   700 {
   701   uint32_t callNumbers = mCurrentCallArray.Length();
   702   uint32_t i;
   703   for (i = 1; i < callNumbers; i++) {
   704     SendCLCC(mCurrentCallArray[i], i);
   705   }
   707   if (!mCdmaSecondCall.mNumber.IsEmpty()) {
   708     MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
   709     MOZ_ASSERT(i == 2);
   711     SendCLCC(mCdmaSecondCall, 2);
   712   }
   714   SendResponse(BTHF_AT_RESPONSE_OK);
   715 }
   717 void
   718 BluetoothHfpManager::ProcessUnknownAt(char *aAtString)
   719 {
   720   BT_LOGR("[%s]", aAtString);
   722   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
   723   NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
   724     sBluetoothHfpInterface->at_response(BTHF_AT_RESPONSE_ERROR, 0));
   725 }
   727 void
   728 BluetoothHfpManager::ProcessKeyPressed()
   729 {
   730   bool hasActiveCall =
   731     (FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED) > 0);
   733   // Refer to AOSP HeadsetStateMachine.processKeyPressed
   734   if (FindFirstCall(nsITelephonyProvider::CALL_STATE_INCOMING)
   735       && !hasActiveCall) {
   736     /**
   737      * Bluetooth HSP spec 4.2.2
   738      * There is an incoming call, notify Dialer to pick up the phone call
   739      * and SCO will be established after we get the CallStateChanged event
   740      * indicating the call is answered successfully.
   741      */
   742     ProcessAnswerCall();
   743   } else if (hasActiveCall) {
   744     if (!IsScoConnected()) {
   745       /**
   746        * Bluetooth HSP spec 4.3
   747        * If there's no SCO, set up a SCO link.
   748        */
   749       ConnectSco();
   750     } else {
   751       /**
   752        * Bluetooth HSP spec 4.5
   753        * There are two ways to release SCO: sending CHUP to dialer or closing
   754        * SCO socket directly. We notify dialer only if there is at least one
   755        * active call.
   756        */
   757       ProcessHangupCall();
   758     }
   759   } else {
   760     // BLDN
   761     mDialingRequestProcessed = false;
   762     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
   763                         NS_LITERAL_STRING("BLDN"));
   764     BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN);
   765   }
   766 }
   768 void
   769 BluetoothHfpManager::NotifyConnectionStateChanged(const nsAString& aType)
   770 {
   771   MOZ_ASSERT(NS_IsMainThread());
   773   // Notify Gecko observers
   774   nsCOMPtr<nsIObserverService> obs =
   775     do_GetService("@mozilla.org/observer-service;1");
   776   NS_ENSURE_TRUE_VOID(obs);
   778   if (NS_FAILED(obs->NotifyObservers(this, NS_ConvertUTF16toUTF8(aType).get(),
   779                                      mDeviceAddress.get()))) {
   780     BT_WARNING("Failed to notify observsers!");
   781   }
   783   // Dispatch an event of status change
   784   bool status;
   785   nsAutoString eventName;
   786   if (aType.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
   787     status = IsConnected();
   788     eventName.AssignLiteral(HFP_STATUS_CHANGED_ID);
   789   } else if (aType.EqualsLiteral(BLUETOOTH_SCO_STATUS_CHANGED_ID)) {
   790     status = IsScoConnected();
   791     eventName.AssignLiteral(SCO_STATUS_CHANGED_ID);
   792   } else {
   793     MOZ_ASSERT(false);
   794     return;
   795   }
   797   DispatchStatusChangedEvent(eventName, mDeviceAddress, status);
   799   // Notify profile controller
   800   if (aType.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
   801     if (IsConnected()) {
   802       MOZ_ASSERT(mListener);
   804       // Enumerate current calls
   805       mListener->EnumerateCalls();
   807       OnConnect(EmptyString());
   808     } else if (mConnectionState == BTHF_CONNECTION_STATE_DISCONNECTED) {
   809       mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
   810       if (mPrevConnectionState == BTHF_CONNECTION_STATE_DISCONNECTED) {
   811         // Bug 979160: This implies the outgoing connection failure.
   812         // When the outgoing hfp connection fails, state changes to disconnected
   813         // state. Since bluedroid would not report connecting state, but only
   814         // report connected/disconnected.
   815         OnConnect(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
   816       } else {
   817         OnDisconnect(EmptyString());
   818       }
   819       Reset();
   820     }
   821   }
   822 }
   824 void
   825 BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
   826 {
   827   NS_NAMED_LITERAL_STRING(type, "bluetooth-dialer-command");
   828   InfallibleTArray<BluetoothNamedValue> parameters;
   830   BT_APPEND_NAMED_VALUE(parameters, "command", nsString(aCommand));
   832   BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
   833 }
   835 void
   836 BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
   837 {
   838   MOZ_ASSERT(NS_IsMainThread());
   840   // The string that we're interested in will be a JSON string that looks like:
   841   //  {"key":"volumeup", "value":10}
   842   //  {"key":"volumedown", "value":2}
   843   JSContext* cx = nsContentUtils::GetSafeJSContext();
   844   NS_ENSURE_TRUE_VOID(cx);
   846   JS::Rooted<JS::Value> val(cx);
   847   NS_ENSURE_TRUE_VOID(JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val));
   848   NS_ENSURE_TRUE_VOID(val.isObject());
   850   JS::Rooted<JSObject*> obj(cx, &val.toObject());
   851   JS::Rooted<JS::Value> key(cx);
   852   if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
   853     return;
   854   }
   856   bool match;
   857   if (!JS_StringEqualsAscii(cx, key.toString(), AUDIO_VOLUME_BT_SCO_ID, &match) ||
   858       !match) {
   859     return;
   860   }
   862   JS::Rooted<JS::Value> value(cx);
   863   if (!JS_GetProperty(cx, obj, "value", &value) ||
   864       !value.isNumber()) {
   865     return;
   866   }
   868   mCurrentVgs = value.toNumber();
   870   // Adjust volume by headset and we don't have to send volume back to headset
   871   if (mReceiveVgsFlag) {
   872     mReceiveVgsFlag = false;
   873     return;
   874   }
   876   // Only send volume back when there's a connected headset
   877   if (IsConnected()) {
   878     NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
   879     NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
   880       sBluetoothHfpInterface->volume_control(BTHF_VOLUME_TYPE_SPK,
   881                                              mCurrentVgs));
   882   }
   883 }
   885 void
   886 BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId)
   887 {
   888   nsCOMPtr<nsIMobileConnectionProvider> connection =
   889     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   890   NS_ENSURE_TRUE_VOID(connection);
   892   nsCOMPtr<nsIDOMMozMobileConnectionInfo> voiceInfo;
   893   connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo));
   894   NS_ENSURE_TRUE_VOID(voiceInfo);
   896   nsString type;
   897   voiceInfo->GetType(type);
   898   mPhoneType = GetPhoneType(type);
   900   bool roaming;
   901   voiceInfo->GetRoaming(&roaming);
   902   mRoam = (roaming) ? 1 : 0;
   904   // Service
   905   nsString regState;
   906   voiceInfo->GetState(regState);
   907   mService = (regState.EqualsLiteral("registered")) ? 1 : 0;
   909   // Signal
   910   JSContext* cx = nsContentUtils::GetSafeJSContext();
   911   NS_ENSURE_TRUE_VOID(cx);
   912   JS::Rooted<JS::Value> value(cx);
   913   voiceInfo->GetRelSignalStrength(&value);
   914   NS_ENSURE_TRUE_VOID(value.isNumber());
   915   mSignal = (int)ceil(value.toNumber() / 20.0);
   917   UpdateDeviceCIND();
   919   // Operator name
   920   nsCOMPtr<nsIDOMMozMobileNetworkInfo> network;
   921   voiceInfo->GetNetwork(getter_AddRefs(network));
   922   NS_ENSURE_TRUE_VOID(network);
   923   network->GetLongName(mOperatorName);
   925   // According to GSM 07.07, "<format> indicates if the format is alphanumeric
   926   // or numeric; long alphanumeric format can be upto 16 characters long and
   927   // short format up to 8 characters (refer GSM MoU SE.13 [9])..."
   928   // However, we found that the operator name may sometimes be longer than 16
   929   // characters. After discussion, we decided to fix this here but not in RIL
   930   // or modem.
   931   //
   932   // Please see Bug 871366 for more information.
   933   if (mOperatorName.Length() > 16) {
   934     BT_WARNING("The operator name was longer than 16 characters. We cut it.");
   935     mOperatorName.Left(mOperatorName, 16);
   936   }
   937 }
   939 void
   940 BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
   941 {
   942   nsCOMPtr<nsIIccProvider> icc =
   943     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   944   NS_ENSURE_TRUE_VOID(icc);
   946   nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
   947   icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
   948   NS_ENSURE_TRUE_VOID(iccInfo);
   950   nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
   951   NS_ENSURE_TRUE_VOID(gsmIccInfo);
   952   gsmIccInfo->GetMsisdn(mMsisdn);
   953 }
   955 void
   956 BluetoothHfpManager::HandleShutdown()
   957 {
   958   MOZ_ASSERT(NS_IsMainThread());
   959   sInShutdown = true;
   960   Disconnect(nullptr);
   961   DisconnectSco();
   962   sBluetoothHfpManager = nullptr;
   963 }
   965 void
   966 BluetoothHfpManager::SendCLCC(Call& aCall, int aIndex)
   967 {
   968   NS_ENSURE_TRUE_VOID(aCall.mState !=
   969                         nsITelephonyProvider::CALL_STATE_DISCONNECTED);
   970   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
   972   bthf_call_state_t callState = ConvertToBthfCallState(aCall.mState);
   974   if (mPhoneType == PhoneType::CDMA && aIndex == 1 && aCall.IsActive()) {
   975     callState = (mCdmaSecondCall.IsActive()) ? BTHF_CALL_STATE_HELD :
   976                                                BTHF_CALL_STATE_ACTIVE;
   977   }
   979   if (callState == BTHF_CALL_STATE_INCOMING &&
   980       FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED)) {
   981     callState = BTHF_CALL_STATE_WAITING;
   982   }
   984   bt_status_t status = sBluetoothHfpInterface->clcc_response(
   985                           aIndex,
   986                           aCall.mDirection,
   987                           callState,
   988                           BTHF_CALL_TYPE_VOICE,
   989                           BTHF_CALL_MPTY_TYPE_SINGLE,
   990                           NS_ConvertUTF16toUTF8(aCall.mNumber).get(),
   991                           aCall.mType);
   992   NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS);
   993 }
   995 void
   996 BluetoothHfpManager::SendLine(const char* aMessage)
   997 {
   998   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
   999   NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
  1000     sBluetoothHfpInterface->formatted_at_response(aMessage));
  1003 void
  1004 BluetoothHfpManager::SendResponse(bthf_at_response_t aResponseCode)
  1006   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
  1007   NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
  1008     sBluetoothHfpInterface->at_response(aResponseCode, 0));
  1011 void
  1012 BluetoothHfpManager::UpdatePhoneCIND(uint32_t aCallIndex)
  1014   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
  1016   int numActive = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_CONNECTED);
  1017   int numHeld = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_HELD);
  1018   bthf_call_state_t callSetupState =
  1019     ConvertToBthfCallState(GetCallSetupState());
  1020   nsAutoCString number =
  1021     NS_ConvertUTF16toUTF8(mCurrentCallArray[aCallIndex].mNumber);
  1022   bthf_call_addrtype_t type = mCurrentCallArray[aCallIndex].mType;
  1024   BT_LOGR("[%d] state %d => BTHF: active[%d] held[%d] setupstate[%d]",
  1025           aCallIndex, mCurrentCallArray[aCallIndex].mState,
  1026           numActive, numHeld, callSetupState);
  1028   NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
  1029     sBluetoothHfpInterface->phone_state_change(
  1030       numActive, numHeld, callSetupState, number.get(), type));
  1033 void
  1034 BluetoothHfpManager::UpdateDeviceCIND()
  1036   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
  1037   NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
  1038     sBluetoothHfpInterface->device_status_notification(
  1039       (bthf_network_state_t) mService,
  1040       (bthf_service_type_t) mRoam,
  1041       mSignal,
  1042       mBattChg));
  1045 uint32_t
  1046 BluetoothHfpManager::FindFirstCall(uint16_t aState)
  1048   uint32_t callLength = mCurrentCallArray.Length();
  1050   for (uint32_t i = 1; i < callLength; ++i) {
  1051     if (mCurrentCallArray[i].mState == aState) {
  1052       return i;
  1056   return 0;
  1059 uint32_t
  1060 BluetoothHfpManager::GetNumberOfCalls(uint16_t aState)
  1062   uint32_t num = 0;
  1063   uint32_t callLength = mCurrentCallArray.Length();
  1065   for (uint32_t i = 1; i < callLength; ++i) {
  1066     if (mCurrentCallArray[i].mState == aState) {
  1067       ++num;
  1071   return num;
  1074 uint16_t
  1075 BluetoothHfpManager::GetCallSetupState()
  1077   uint32_t callLength = mCurrentCallArray.Length();
  1079   for (uint32_t i = 1; i < callLength; ++i) {
  1080     switch (mCurrentCallArray[i].mState) {
  1081       case nsITelephonyProvider::CALL_STATE_INCOMING:
  1082       case nsITelephonyProvider::CALL_STATE_DIALING:
  1083       case nsITelephonyProvider::CALL_STATE_ALERTING:
  1084         return mCurrentCallArray[i].mState;
  1085       default:
  1086         break;
  1090   return nsITelephonyProvider::CALL_STATE_DISCONNECTED;
  1093 bthf_call_state_t
  1094 BluetoothHfpManager::ConvertToBthfCallState(int aCallState)
  1096   bthf_call_state_t state;
  1098   // Refer to AOSP BluetoothPhoneService.convertCallState
  1099   if (aCallState == nsITelephonyProvider::CALL_STATE_INCOMING) {
  1100     state = BTHF_CALL_STATE_INCOMING;
  1101   } else if (aCallState == nsITelephonyProvider::CALL_STATE_DIALING) {
  1102     state = BTHF_CALL_STATE_DIALING;
  1103   } else if (aCallState == nsITelephonyProvider::CALL_STATE_ALERTING) {
  1104     state = BTHF_CALL_STATE_ALERTING;
  1105   } else if (aCallState == nsITelephonyProvider::CALL_STATE_CONNECTED) {
  1106     state = BTHF_CALL_STATE_ACTIVE;
  1107   } else if (aCallState == nsITelephonyProvider::CALL_STATE_HELD) {
  1108     state = BTHF_CALL_STATE_HELD;
  1109   } else { // disconnected
  1110     state = BTHF_CALL_STATE_IDLE;
  1113   return state;
  1116 bool
  1117 BluetoothHfpManager::IsTransitionState(uint16_t aCallState, bool aIsConference)
  1119   /**
  1120    * Regard this callstate change as during CHLD=2 transition state if
  1121    * - the call becomes active, and numActive > 1
  1122    * - the call becomes held, and numHeld > 1 or an incoming call exists
  1124    * TODO:
  1125    * 1) handle CHLD=1 transition state
  1126    * 2) handle conference call cases
  1127    */
  1128   if (!aIsConference) {
  1129     switch (aCallState) {
  1130       case nsITelephonyProvider::CALL_STATE_CONNECTED:
  1131         return (GetNumberOfCalls(aCallState) > 1);
  1132       case nsITelephonyProvider::CALL_STATE_HELD:
  1133         return (GetNumberOfCalls(aCallState) > 1 ||
  1134                 FindFirstCall(nsITelephonyProvider::CALL_STATE_INCOMING));
  1135       default:
  1136         break;
  1140   return false;
  1143 void
  1144 BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
  1145                                             uint16_t aCallState,
  1146                                             const nsAString& aError,
  1147                                             const nsAString& aNumber,
  1148                                             const bool aIsOutgoing,
  1149                                             const bool aIsConference,
  1150                                             bool aSend)
  1152   // aCallIndex can be UINT32_MAX for the pending outgoing call state update.
  1153   // aCallIndex will be updated again after real call state changes. See Bug
  1154   // 990467.
  1155   if (aCallIndex == UINT32_MAX) {
  1156     return;
  1159   // Update call state only
  1160   while (aCallIndex >= mCurrentCallArray.Length()) {
  1161     Call call;
  1162     mCurrentCallArray.AppendElement(call);
  1164   mCurrentCallArray[aCallIndex].mState = aCallState;
  1166   // Return if SLC is disconnected
  1167   if (!IsConnected()) {
  1168     return;
  1171   // Update call information besides call state
  1172   mCurrentCallArray[aCallIndex].Set(aNumber, aIsOutgoing);
  1174   // Notify bluedroid of phone state change if this
  1175   // call state change is not during transition state
  1176   if (!IsTransitionState(aCallState, aIsConference)) {
  1177     UpdatePhoneCIND(aCallIndex);
  1180   switch (aCallState) {
  1181     case nsITelephonyProvider::CALL_STATE_DIALING:
  1182       // We've send Dialer a dialing request and this is the response.
  1183       if (!mDialingRequestProcessed) {
  1184         SendResponse(BTHF_AT_RESPONSE_OK);
  1185         mDialingRequestProcessed = true;
  1187       break;
  1188     case nsITelephonyProvider::CALL_STATE_DISCONNECTED:
  1189       // -1 is necessary because call 0 is an invalid (padding) call object.
  1190       if (mCurrentCallArray.Length() - 1 ==
  1191           GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_DISCONNECTED)) {
  1192         // In order to let user hear busy tone via connected Bluetooth headset,
  1193         // we postpone the timing of dropping SCO.
  1194         if (aError.Equals(NS_LITERAL_STRING("BusyError"))) {
  1195           // FIXME: UpdatePhoneCIND later since it causes SCO close but
  1196           // Dialer is still playing busy tone via HF.
  1197           BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_CLOSE_SCO);
  1200         ResetCallArray();
  1202       break;
  1203     default:
  1204       break;
  1208 PhoneType
  1209 BluetoothHfpManager::GetPhoneType(const nsAString& aType)
  1211   // FIXME: Query phone type from RIL after RIL implements new API (bug 912019)
  1212   if (aType.EqualsLiteral("gsm") || aType.EqualsLiteral("gprs") ||
  1213       aType.EqualsLiteral("edge") || aType.EqualsLiteral("umts") ||
  1214       aType.EqualsLiteral("hspa") || aType.EqualsLiteral("hsdpa") ||
  1215       aType.EqualsLiteral("hsupa") || aType.EqualsLiteral("hspa+")) {
  1216     return PhoneType::GSM;
  1217   } else if (aType.EqualsLiteral("is95a") || aType.EqualsLiteral("is95b") ||
  1218              aType.EqualsLiteral("1xrtt") || aType.EqualsLiteral("evdo0") ||
  1219              aType.EqualsLiteral("evdoa") || aType.EqualsLiteral("evdob")) {
  1220     return PhoneType::CDMA;
  1223   return PhoneType::NONE;
  1226 void
  1227 BluetoothHfpManager::UpdateSecondNumber(const nsAString& aNumber)
  1229   MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
  1231   // Always regard second call as incoming call since v1.2 RIL
  1232   // doesn't support outgoing second call in CDMA.
  1233   mCdmaSecondCall.Set(aNumber, false);
  1235   // FIXME: check CDMA + bluedroid
  1236   //UpdateCIND(CINDType::CALLSETUP, CallSetupState::INCOMING, true);
  1239 void
  1240 BluetoothHfpManager::AnswerWaitingCall()
  1242   MOZ_ASSERT(NS_IsMainThread());
  1243   MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
  1245   // Pick up second call. First call is held now.
  1246   mCdmaSecondCall.mState = nsITelephonyProvider::CALL_STATE_CONNECTED;
  1247   // FIXME: check CDMA + bluedroid
  1248   //UpdateCIND(CINDType::CALLSETUP, CallSetupState::NO_CALLSETUP, true);
  1250   //sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_ACTIVE;
  1251   //SendCommand("+CIEV: ", CINDType::CALLHELD);
  1254 void
  1255 BluetoothHfpManager::IgnoreWaitingCall()
  1257   MOZ_ASSERT(NS_IsMainThread());
  1258   MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
  1260   mCdmaSecondCall.Reset();
  1261   // FIXME: check CDMA + bluedroid
  1262   //UpdateCIND(CINDType::CALLSETUP, CallSetupState::NO_CALLSETUP, true);
  1265 void
  1266 BluetoothHfpManager::ToggleCalls()
  1268   MOZ_ASSERT(NS_IsMainThread());
  1269   MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
  1271   // Toggle acitve and held calls
  1272   mCdmaSecondCall.mState = (mCdmaSecondCall.IsActive()) ?
  1273                              nsITelephonyProvider::CALL_STATE_HELD :
  1274                              nsITelephonyProvider::CALL_STATE_CONNECTED;
  1277 bool
  1278 BluetoothHfpManager::ConnectSco()
  1280   MOZ_ASSERT(NS_IsMainThread());
  1282   NS_ENSURE_TRUE(!sInShutdown, false);
  1283   NS_ENSURE_TRUE(IsConnected() && !IsScoConnected(), false);
  1284   NS_ENSURE_TRUE(sBluetoothHfpInterface, false);
  1286   bt_bdaddr_t deviceBdAddress;
  1287   StringToBdAddressType(mDeviceAddress, &deviceBdAddress);
  1288   NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
  1289     sBluetoothHfpInterface->connect_audio(&deviceBdAddress), false);
  1291   return true;
  1294 bool
  1295 BluetoothHfpManager::DisconnectSco()
  1297   NS_ENSURE_TRUE(IsScoConnected(), false);
  1298   NS_ENSURE_TRUE(sBluetoothHfpInterface, false);
  1300   bt_bdaddr_t deviceBdAddress;
  1301   StringToBdAddressType(mDeviceAddress, &deviceBdAddress);
  1302   NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
  1303     sBluetoothHfpInterface->disconnect_audio(&deviceBdAddress), false);
  1305   return true;
  1308 bool
  1309 BluetoothHfpManager::IsScoConnected()
  1311   return (mAudioState == BTHF_AUDIO_STATE_CONNECTED);
  1314 bool
  1315 BluetoothHfpManager::IsConnected()
  1317   return (mConnectionState == BTHF_CONNECTION_STATE_SLC_CONNECTED);
  1320 void
  1321 BluetoothHfpManager::Connect(const nsAString& aDeviceAddress,
  1322                              BluetoothProfileController* aController)
  1324   MOZ_ASSERT(NS_IsMainThread());
  1325   MOZ_ASSERT(aController && !mController);
  1327   if (sInShutdown) {
  1328     aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
  1329     return;
  1332   if (!sBluetoothHfpInterface) {
  1333     BT_LOGR("sBluetoothHfpInterface is null");
  1334     aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
  1335     return;
  1338   bt_bdaddr_t deviceBdAddress;
  1339   StringToBdAddressType(aDeviceAddress, &deviceBdAddress);
  1341   bt_status_t result = sBluetoothHfpInterface->connect(&deviceBdAddress);
  1342   if (BT_STATUS_SUCCESS != result) {
  1343     BT_LOGR("Failed to connect: %x", result);
  1344     aController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
  1345     return;
  1348   mDeviceAddress = aDeviceAddress;
  1349   mController = aController;
  1352 void
  1353 BluetoothHfpManager::Disconnect(BluetoothProfileController* aController)
  1355   MOZ_ASSERT(NS_IsMainThread());
  1356   MOZ_ASSERT(!mController);
  1358   if (!sBluetoothHfpInterface) {
  1359     BT_LOGR("sBluetoothHfpInterface is null");
  1360     aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
  1361     return;
  1364   bt_bdaddr_t deviceBdAddress;
  1365   StringToBdAddressType(mDeviceAddress, &deviceBdAddress);
  1367   bt_status_t result = sBluetoothHfpInterface->disconnect(&deviceBdAddress);
  1368   if (BT_STATUS_SUCCESS != result) {
  1369     BT_LOGR("Failed to disconnect: %x", result);
  1370     aController->NotifyCompletion(NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
  1371     return;
  1374   mController = aController;
  1377 void
  1378 BluetoothHfpManager::OnConnect(const nsAString& aErrorStr)
  1380   MOZ_ASSERT(NS_IsMainThread());
  1382   /**
  1383    * On the one hand, notify the controller that we've done for outbound
  1384    * connections. On the other hand, we do nothing for inbound connections.
  1385    */
  1386   NS_ENSURE_TRUE_VOID(mController);
  1388   mController->NotifyCompletion(aErrorStr);
  1389   mController = nullptr;
  1392 void
  1393 BluetoothHfpManager::OnDisconnect(const nsAString& aErrorStr)
  1395   MOZ_ASSERT(NS_IsMainThread());
  1397   /**
  1398    * On the one hand, notify the controller that we've done for outbound
  1399    * connections. On the other hand, we do nothing for inbound connections.
  1400    */
  1401   NS_ENSURE_TRUE_VOID(mController);
  1403   mController->NotifyCompletion(aErrorStr);
  1404   mController = nullptr;
  1407 void
  1408 BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
  1410   // Bluedroid handles this part
  1411   MOZ_ASSERT(false);
  1414 void
  1415 BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
  1416                                          const nsAString& aServiceUuid,
  1417                                          int aChannel)
  1419   // Bluedroid handles this part
  1420   MOZ_ASSERT(false);
  1423 void
  1424 BluetoothHfpManager::GetAddress(nsAString& aDeviceAddress)
  1426   aDeviceAddress = mDeviceAddress;
  1429 NS_IMPL_ISUPPORTS(BluetoothHfpManager, nsIObserver)

mercurial