michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "BluetoothRilListener.h" michael@0: michael@0: #include "BluetoothHfpManager.h" michael@0: #include "nsIDOMMobileConnection.h" michael@0: #include "nsIRadioInterfaceLayer.h" michael@0: #include "nsRadioInterfaceLayer.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsString.h" michael@0: michael@0: USING_BLUETOOTH_NAMESPACE michael@0: michael@0: /** michael@0: * IccListener michael@0: */ michael@0: NS_IMPL_ISUPPORTS(IccListener, nsIIccListener) michael@0: michael@0: NS_IMETHODIMP michael@0: IccListener::NotifyIccInfoChanged() michael@0: { michael@0: // mOwner would be set to nullptr only in the dtor of BluetoothRilListener michael@0: NS_ENSURE_TRUE(mOwner, NS_ERROR_FAILURE); michael@0: michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE); michael@0: michael@0: hfp->HandleIccInfoChanged(mOwner->mClientId); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: IccListener::NotifyStkCommand(const nsAString & aMessage) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: IccListener::NotifyStkSessionEnd() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: IccListener::NotifyCardStateChanged() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: IccListener::Listen(bool aStart) michael@0: { michael@0: NS_ENSURE_TRUE(mOwner, false); michael@0: michael@0: nsCOMPtr provider = michael@0: do_GetService(NS_RILCONTENTHELPER_CONTRACTID); michael@0: NS_ENSURE_TRUE(provider, false); michael@0: michael@0: nsresult rv; michael@0: if (aStart) { michael@0: rv = provider->RegisterIccMsg(mOwner->mClientId, this); michael@0: } else { michael@0: rv = provider->UnregisterIccMsg(mOwner->mClientId, this); michael@0: } michael@0: michael@0: return NS_SUCCEEDED(rv); michael@0: } michael@0: michael@0: void michael@0: IccListener::SetOwner(BluetoothRilListener *aOwner) michael@0: { michael@0: mOwner = aOwner; michael@0: } michael@0: michael@0: /** michael@0: * MobileConnectionListener michael@0: */ michael@0: NS_IMPL_ISUPPORTS(MobileConnectionListener, nsIMobileConnectionListener) michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyVoiceChanged() michael@0: { michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: NS_ENSURE_TRUE(hfp, NS_OK); michael@0: michael@0: hfp->HandleVoiceConnectionChanged(mClientId); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyDataChanged() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyUssdReceived(const nsAString & message, michael@0: bool sessionEnded) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyDataError(const nsAString & message) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyCFStateChange(bool success, michael@0: uint16_t action, michael@0: uint16_t reason, michael@0: const nsAString& number, michael@0: uint16_t timeSeconds, michael@0: uint16_t serviceClass) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyEmergencyCbModeChanged(bool active, michael@0: uint32_t timeoutMs) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyOtaStatusChanged(const nsAString & status) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyIccChanged() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileConnectionListener::NotifyRadioStateChanged() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: MobileConnectionListener::Listen(bool aStart) michael@0: { michael@0: nsCOMPtr provider = michael@0: do_GetService(NS_RILCONTENTHELPER_CONTRACTID); michael@0: NS_ENSURE_TRUE(provider, false); michael@0: michael@0: nsresult rv; michael@0: if (aStart) { michael@0: rv = provider->RegisterMobileConnectionMsg(mClientId, this); michael@0: } else { michael@0: rv = provider->UnregisterMobileConnectionMsg(mClientId, this); michael@0: } michael@0: michael@0: return NS_SUCCEEDED(rv); michael@0: } michael@0: michael@0: /** michael@0: * TelephonyListener Implementation michael@0: */ michael@0: NS_IMPL_ISUPPORTS(TelephonyListener, nsITelephonyListener) michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::CallStateChanged(uint32_t aServiceId, michael@0: uint32_t aCallIndex, michael@0: uint16_t aCallState, michael@0: const nsAString& aNumber, michael@0: bool aIsActive, michael@0: bool aIsOutgoing, michael@0: bool aIsEmergency, michael@0: bool aIsConference, michael@0: bool aIsSwitchable, michael@0: bool aIsMergeable) michael@0: { michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE); michael@0: michael@0: hfp->HandleCallStateChanged(aCallIndex, aCallState, EmptyString(), aNumber, michael@0: aIsOutgoing, aIsConference, true); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::EnumerateCallState(uint32_t aServiceId, michael@0: uint32_t aCallIndex, michael@0: uint16_t aCallState, michael@0: const nsAString_internal& aNumber, michael@0: bool aIsActive, michael@0: bool aIsOutgoing, michael@0: bool aIsEmergency, michael@0: bool aIsConference, michael@0: bool aIsSwitchable, michael@0: bool aIsMergeable) michael@0: { michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE); michael@0: michael@0: hfp->HandleCallStateChanged(aCallIndex, aCallState, EmptyString(), aNumber, michael@0: aIsOutgoing, aIsConference, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::NotifyError(uint32_t aServiceId, michael@0: int32_t aCallIndex, michael@0: const nsAString& aError) michael@0: { michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE); michael@0: michael@0: if (aCallIndex > 0) { michael@0: // In order to not miss any related call state transition. michael@0: // It's possible that 3G network signal lost for unknown reason. michael@0: // If a call is released abnormally, NotifyError() will be called, michael@0: // instead of CallStateChanged(). We need to reset the call array state michael@0: // via setting CALL_STATE_DISCONNECTED michael@0: hfp->HandleCallStateChanged(aCallIndex, michael@0: nsITelephonyProvider::CALL_STATE_DISCONNECTED, michael@0: aError, EmptyString(), false, false, true); michael@0: BT_WARNING("Reset the call state due to call transition ends abnormally"); michael@0: } michael@0: michael@0: BT_WARNING(NS_ConvertUTF16toUTF8(aError).get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::ConferenceCallStateChanged(uint16_t aCallState) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::EnumerateCallStateComplete() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::SupplementaryServiceNotification(uint32_t aServiceId, michael@0: int32_t aCallIndex, michael@0: uint16_t aNotification) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::NotifyConferenceError(const nsAString& aName, michael@0: const nsAString& aMessage) michael@0: { michael@0: BT_WARNING(NS_ConvertUTF16toUTF8(aName).get()); michael@0: BT_WARNING(NS_ConvertUTF16toUTF8(aMessage).get()); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TelephonyListener::NotifyCdmaCallWaiting(uint32_t aServiceId, michael@0: const nsAString& aNumber) michael@0: { michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE); michael@0: michael@0: hfp->UpdateSecondNumber(aNumber); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: TelephonyListener::Listen(bool aStart) michael@0: { michael@0: nsCOMPtr provider = michael@0: do_GetService(TELEPHONY_PROVIDER_CONTRACTID); michael@0: NS_ENSURE_TRUE(provider, false); michael@0: michael@0: nsresult rv; michael@0: if (aStart) { michael@0: rv = provider->RegisterListener(this); michael@0: } else { michael@0: rv = provider->UnregisterListener(this); michael@0: } michael@0: michael@0: return NS_SUCCEEDED(rv); michael@0: } michael@0: michael@0: /** michael@0: * BluetoothRilListener michael@0: */ michael@0: BluetoothRilListener::BluetoothRilListener() michael@0: { michael@0: // Query number of total clients (sim slots) michael@0: uint32_t numOfClients; michael@0: nsCOMPtr radioInterfaceLayer = michael@0: do_GetService(NS_RADIOINTERFACELAYER_CONTRACTID); michael@0: NS_ENSURE_TRUE_VOID(radioInterfaceLayer); michael@0: michael@0: radioInterfaceLayer->GetNumRadioInterfaces(&numOfClients); michael@0: michael@0: // Init MobileConnectionListener array and IccInfoListener michael@0: for (uint32_t i = 0; i < numOfClients; i++) { michael@0: mMobileConnListeners.AppendElement(new MobileConnectionListener(i)); michael@0: } michael@0: michael@0: mTelephonyListener = new TelephonyListener(); michael@0: mIccListener = new IccListener(); michael@0: mIccListener->SetOwner(this); michael@0: michael@0: // Probe for available client michael@0: SelectClient(); michael@0: } michael@0: michael@0: BluetoothRilListener::~BluetoothRilListener() michael@0: { michael@0: mIccListener->SetOwner(nullptr); michael@0: } michael@0: michael@0: bool michael@0: BluetoothRilListener::Listen(bool aStart) michael@0: { michael@0: NS_ENSURE_TRUE(ListenMobileConnAndIccInfo(aStart), false); michael@0: NS_ENSURE_TRUE(mTelephonyListener->Listen(aStart), false); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: BluetoothRilListener::SelectClient() michael@0: { michael@0: // Reset mClientId michael@0: mClientId = mMobileConnListeners.Length(); michael@0: michael@0: nsCOMPtr connection = michael@0: do_GetService(NS_RILCONTENTHELPER_CONTRACTID); michael@0: NS_ENSURE_TRUE_VOID(connection); michael@0: michael@0: for (uint32_t i = 0; i < mMobileConnListeners.Length(); i++) { michael@0: nsCOMPtr voiceInfo; michael@0: connection->GetVoiceConnectionInfo(i, getter_AddRefs(voiceInfo)); michael@0: if (!voiceInfo) { michael@0: BT_WARNING("%s: Failed to get voice connection info", __FUNCTION__); michael@0: continue; michael@0: } michael@0: michael@0: nsString regState; michael@0: voiceInfo->GetState(regState); michael@0: if (regState.EqualsLiteral("registered")) { michael@0: // Found available client michael@0: mClientId = i; michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: BluetoothRilListener::ServiceChanged(uint32_t aClientId, bool aRegistered) michael@0: { michael@0: // Stop listening michael@0: ListenMobileConnAndIccInfo(false); michael@0: michael@0: /** michael@0: * aRegistered: michael@0: * - TRUE: service becomes registered. We were listening to all clients michael@0: * and one of them becomes available. Select it to listen. michael@0: * - FALSE: service becomes un-registered. The client we were listening michael@0: * becomes unavailable. Select another registered one to listen. michael@0: */ michael@0: if (aRegistered) { michael@0: mClientId = aClientId; michael@0: } else { michael@0: SelectClient(); michael@0: } michael@0: michael@0: // Restart listening michael@0: ListenMobileConnAndIccInfo(true); michael@0: michael@0: BT_LOGR("%d client %d. new mClientId %d", aRegistered, aClientId, michael@0: (mClientId < mMobileConnListeners.Length()) ? mClientId : -1); michael@0: } michael@0: michael@0: void michael@0: BluetoothRilListener::EnumerateCalls() michael@0: { michael@0: nsCOMPtr provider = michael@0: do_GetService(TELEPHONY_PROVIDER_CONTRACTID); michael@0: NS_ENSURE_TRUE_VOID(provider); michael@0: michael@0: nsCOMPtr listener( michael@0: do_QueryObject(mTelephonyListener)); michael@0: michael@0: provider->EnumerateCalls(listener); michael@0: } michael@0: michael@0: bool michael@0: BluetoothRilListener::ListenMobileConnAndIccInfo(bool aStart) michael@0: { michael@0: /** michael@0: * mClientId < number of total clients: michael@0: * The client with mClientId is available. Start/Stop listening michael@0: * mobile connection and icc info of this client only. michael@0: * michael@0: * mClientId >= number of total clients: michael@0: * All clients are unavailable. Start/Stop listening mobile michael@0: * connections of all clients. michael@0: */ michael@0: if (mClientId < mMobileConnListeners.Length()) { michael@0: NS_ENSURE_TRUE(mMobileConnListeners[mClientId]->Listen(aStart), false); michael@0: NS_ENSURE_TRUE(mIccListener->Listen(aStart), false); michael@0: } else { michael@0: for (uint32_t i = 0; i < mMobileConnListeners.Length(); i++) { michael@0: NS_ENSURE_TRUE(mMobileConnListeners[i]->Listen(aStart), false); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: }