/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/MobileConnection.h" #include "MobileConnectionCallback.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/dom/CFStateChangeEvent.h" #include "mozilla/dom/DataErrorEvent.h" #include "mozilla/dom/MozClirModeEvent.h" #include "mozilla/dom/MozEmergencyCbModeEvent.h" #include "mozilla/dom/MozOtaStatusEvent.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsIDOMDOMRequest.h" #include "nsIIccInfo.h" #include "nsIPermissionManager.h" #include "nsIVariant.h" #include "nsJSON.h" #include "nsJSUtils.h" #include "nsServiceManagerUtils.h" #define MOBILECONN_ERROR_INVALID_PARAMETER NS_LITERAL_STRING("InvalidParameter") #define MOBILECONN_ERROR_INVALID_PASSWORD NS_LITERAL_STRING("InvalidPassword") #ifdef CONVERT_STRING_TO_NULLABLE_ENUM #undef CONVERT_STRING_TO_NULLABLE_ENUM #endif #define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum) \ { \ uint32_t i = 0; \ for (const EnumEntry* entry = _enumType##Values::strings; \ entry->value; \ ++entry, ++i) { \ if (_string.EqualsASCII(entry->value)) { \ _enum.SetValue(static_cast<_enumType>(i)); \ } \ } \ } using mozilla::ErrorResult; using namespace mozilla::dom; using namespace mozilla::dom::mobileconnection; class MobileConnection::Listener final : public nsIMobileConnectionListener , public nsIIccListener { MobileConnection* mMobileConnection; public: NS_DECL_ISUPPORTS NS_FORWARD_SAFE_NSIMOBILECONNECTIONLISTENER(mMobileConnection) NS_FORWARD_SAFE_NSIICCLISTENER(mMobileConnection) explicit Listener(MobileConnection* aMobileConnection) : mMobileConnection(aMobileConnection) { MOZ_ASSERT(mMobileConnection); } void Disconnect() { MOZ_ASSERT(mMobileConnection); mMobileConnection = nullptr; } private: ~Listener() { MOZ_ASSERT(!mMobileConnection); } }; NS_IMPL_ISUPPORTS(MobileConnection::Listener, nsIMobileConnectionListener, nsIIccListener) NS_IMPL_CYCLE_COLLECTION_CLASS(MobileConnection) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MobileConnection, DOMEventTargetHelper) // Don't traverse mListener because it doesn't keep any reference to // MobileConnection but a raw pointer instead. Neither does mMobileConnection // because it's an xpcom service owned object and is only released at shutting // down. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoice) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccHandler) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MobileConnection, DOMEventTargetHelper) tmp->Shutdown(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mVoice) NS_IMPL_CYCLE_COLLECTION_UNLINK(mData) NS_IMPL_CYCLE_COLLECTION_UNLINK(mIccHandler) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MobileConnection) // MobileConnection does not expose nsIMobileConnectionListener. mListener is // the exposed nsIMobileConnectionListener and forwards the calls it receives // to us. NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(MobileConnection, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(MobileConnection, DOMEventTargetHelper) MobileConnection::MobileConnection(nsPIDOMWindow* aWindow, uint32_t aClientId) : DOMEventTargetHelper(aWindow) , mClientId(aClientId) { nsCOMPtr service = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); // Per WebAPI design, mIccId should be null instead of an empty string when no // SIM card is inserted. Set null as default value. mIccId.SetIsVoid(true); // Not being able to acquire the service isn't fatal since we check // for it explicitly below. if (!service) { NS_WARNING("Could not acquire nsIMobileConnectionService!"); return; } nsresult rv = service->GetItemByServiceId(mClientId, getter_AddRefs(mMobileConnection)); if (NS_FAILED(rv) || !mMobileConnection) { NS_WARNING("Could not acquire nsIMobileConnection!"); return; } mListener = new Listener(this); mVoice = new MobileConnectionInfo(GetOwner()); mData = new MobileConnectionInfo(GetOwner()); if (CheckPermission("mobileconnection")) { DebugOnly rv = mMobileConnection->RegisterListener(mListener); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed registering mobile connection messages with service"); UpdateVoice(); UpdateData(); nsCOMPtr iccService = do_GetService(ICC_SERVICE_CONTRACTID); if (iccService) { iccService->GetIccByServiceId(mClientId, getter_AddRefs(mIccHandler)); } if (!mIccHandler) { NS_WARNING("Could not acquire nsIMobileConnection or nsIIcc!"); return; } rv = mIccHandler->RegisterListener(mListener); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed registering icc messages with service"); UpdateIccId(); } } void MobileConnection::Shutdown() { if (mListener) { if (mMobileConnection) { mMobileConnection->UnregisterListener(mListener); } if (mIccHandler) { mIccHandler->UnregisterListener(mListener); } mListener->Disconnect(); mListener = nullptr; } } MobileConnection::~MobileConnection() { Shutdown(); } void MobileConnection::DisconnectFromOwner() { DOMEventTargetHelper::DisconnectFromOwner(); // Event listeners can't be handled anymore, so we can shutdown // the MobileConnection. Shutdown(); } JSObject* MobileConnection::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return MozMobileConnectionBinding::Wrap(aCx, this, aGivenProto); } bool MobileConnection::CheckPermission(const char* aType) const { nsCOMPtr permMgr = mozilla::services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission = nsIPermissionManager::DENY_ACTION; permMgr->TestPermissionFromWindow(GetOwner(), aType, &permission); return permission == nsIPermissionManager::ALLOW_ACTION; } void MobileConnection::UpdateVoice() { if (!mMobileConnection) { return; } nsCOMPtr info; mMobileConnection->GetVoice(getter_AddRefs(info)); mVoice->Update(info); } void MobileConnection::UpdateData() { if (!mMobileConnection) { return; } nsCOMPtr info; mMobileConnection->GetData(getter_AddRefs(info)); mData->Update(info); } bool MobileConnection::UpdateIccId() { nsAutoString iccId; nsCOMPtr iccInfo; if (mIccHandler && NS_SUCCEEDED(mIccHandler->GetIccInfo(getter_AddRefs(iccInfo))) && iccInfo) { iccInfo->GetIccid(iccId); } else { iccId.SetIsVoid(true); } if (!mIccId.Equals(iccId)) { mIccId = iccId; return true; } return false; } nsresult MobileConnection::NotifyError(nsIDOMDOMRequest* aRequest, const nsAString& aMessage) { nsCOMPtr rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID); NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE); return rs->FireErrorAsync(aRequest, aMessage); } bool MobileConnection::IsValidPassword(const nsAString& aPassword) { // Check valid PIN for supplementary services. See TS.22.004 clause 5.2. if (aPassword.IsEmpty() || aPassword.Length() != 4) { return false; } nsresult rv; int32_t password = nsString(aPassword).ToInteger(&rv); return NS_SUCCEEDED(rv) && password >= 0 && password <= 9999; } bool MobileConnection::IsValidCallForwardingReason(int32_t aReason) { return aReason >= nsIMobileConnection::CALL_FORWARD_REASON_UNCONDITIONAL && aReason <= nsIMobileConnection::CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING; } bool MobileConnection::IsValidCallForwardingAction(int32_t aAction) { return aAction >= nsIMobileConnection::CALL_FORWARD_ACTION_DISABLE && aAction <= nsIMobileConnection::CALL_FORWARD_ACTION_ERASURE && // Set operation doesn't allow "query" action. aAction != nsIMobileConnection::CALL_FORWARD_ACTION_QUERY_STATUS; } bool MobileConnection::IsValidCallBarringProgram(int32_t aProgram) { return aProgram >= nsIMobileConnection::CALL_BARRING_PROGRAM_ALL_OUTGOING && aProgram <= nsIMobileConnection::CALL_BARRING_PROGRAM_INCOMING_SERVICE; } bool MobileConnection::IsValidCallBarringOptions(const MozCallBarringOptions& aOptions, bool isSetting) { if (!aOptions.mServiceClass.WasPassed() || aOptions.mServiceClass.Value().IsNull() || !aOptions.mProgram.WasPassed() || aOptions.mProgram.Value().IsNull() || !IsValidCallBarringProgram(aOptions.mProgram.Value().Value())) { return false; } // For setting callbarring options, |enabled| and |password| are required. if (isSetting && (!aOptions.mEnabled.WasPassed() || aOptions.mEnabled.Value().IsNull() || !aOptions.mPassword.WasPassed() || aOptions.mPassword.Value().IsVoid())) { return false; } return true; } bool MobileConnection::IsValidCallForwardingOptions(const MozCallForwardingOptions& aOptions) { if (!aOptions.mReason.WasPassed() || aOptions.mReason.Value().IsNull() || !aOptions.mAction.WasPassed() || aOptions.mAction.Value().IsNull() || !IsValidCallForwardingReason(aOptions.mReason.Value().Value()) || !IsValidCallForwardingAction(aOptions.mAction.Value().Value())) { return false; } return true; } // WebIDL interface void MobileConnection::GetLastKnownNetwork(nsString& aRetVal) const { aRetVal.SetIsVoid(true); if (!mMobileConnection) { return; } mMobileConnection->GetLastKnownNetwork(aRetVal); } void MobileConnection::GetLastKnownHomeNetwork(nsString& aRetVal) const { aRetVal.SetIsVoid(true); if (!mMobileConnection) { return; } mMobileConnection->GetLastKnownHomeNetwork(aRetVal); } // All fields below require the "mobileconnection" permission. MobileConnectionInfo* MobileConnection::Voice() const { return mVoice; } MobileConnectionInfo* MobileConnection::Data() const { return mData; } void MobileConnection::GetIccId(nsString& aRetVal) const { aRetVal = mIccId; } Nullable MobileConnection::GetNetworkSelectionMode() const { Nullable retVal = Nullable(); if (!mMobileConnection) { return retVal; } int32_t mode = nsIMobileConnection::NETWORK_SELECTION_MODE_UNKNOWN; if (NS_SUCCEEDED(mMobileConnection->GetNetworkSelectionMode(&mode)) && mode != nsIMobileConnection::NETWORK_SELECTION_MODE_UNKNOWN) { MOZ_ASSERT(mode < static_cast(MobileNetworkSelectionMode::EndGuard_)); retVal.SetValue(static_cast(mode)); } return retVal; } Nullable MobileConnection::GetRadioState() const { Nullable retVal = Nullable(); if (!mMobileConnection) { return retVal; } int32_t state = nsIMobileConnection::MOBILE_RADIO_STATE_UNKNOWN; if (NS_SUCCEEDED(mMobileConnection->GetRadioState(&state)) && state != nsIMobileConnection::MOBILE_RADIO_STATE_UNKNOWN) { MOZ_ASSERT(state < static_cast(MobileRadioState::EndGuard_)); retVal.SetValue(static_cast(state)); } return retVal; } void MobileConnection::GetSupportedNetworkTypes(nsTArray& aTypes) const { if (!mMobileConnection) { return; } int32_t* types = nullptr; uint32_t length = 0; nsresult rv = mMobileConnection->GetSupportedNetworkTypes(&types, &length); NS_ENSURE_SUCCESS_VOID(rv); for (uint32_t i = 0; i < length; ++i) { int32_t type = types[i]; MOZ_ASSERT(type < static_cast(MobileNetworkType::EndGuard_)); aTypes.AppendElement(static_cast(type)); } free(types); } already_AddRefed MobileConnection::GetNetworks(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetNetworks(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SelectNetwork(MobileNetworkInfo& aNetwork, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SelectNetwork(&aNetwork, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SelectNetworkAutomatically(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SelectNetworkAutomatically(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetPreferredNetworkType(MobilePreferredNetworkType& aType, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } int32_t type = static_cast(aType); RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetPreferredNetworkType(type, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::GetPreferredNetworkType(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetPreferredNetworkType(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetRoamingPreference(MobileRoamingMode& aMode, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } int32_t mode = static_cast(aMode); RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetRoamingPreference(mode, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::GetRoamingPreference(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetRoamingPreference(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetVoicePrivacyMode(bool aEnabled, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetVoicePrivacyMode(aEnabled, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::GetVoicePrivacyMode(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetVoicePrivacyMode(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::GetCallForwardingOption(uint16_t aReason, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); if (!IsValidCallForwardingReason(aReason)) { nsresult rv = NotifyError(request, MOBILECONN_ERROR_INVALID_PARAMETER); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetCallForwarding(aReason, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetCallForwardingOption(const MozCallForwardingOptions& aOptions, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); if (!IsValidCallForwardingOptions(aOptions)) { nsresult rv = NotifyError(request, MOBILECONN_ERROR_INVALID_PARAMETER); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } // Fill in optional attributes. uint16_t timeSeconds = 0; if (aOptions.mTimeSeconds.WasPassed() && !aOptions.mTimeSeconds.Value().IsNull()) { timeSeconds = aOptions.mTimeSeconds.Value().Value(); } uint16_t serviceClass = nsIMobileConnection::ICC_SERVICE_CLASS_NONE; if (aOptions.mServiceClass.WasPassed() && !aOptions.mServiceClass.Value().IsNull()) { serviceClass = aOptions.mServiceClass.Value().Value(); } nsAutoString number; if (aOptions.mNumber.WasPassed()) { number = aOptions.mNumber.Value(); } else { number.SetIsVoid(true); } RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetCallForwarding(aOptions.mAction.Value().Value(), aOptions.mReason.Value().Value(), number, timeSeconds, serviceClass, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::GetCallBarringOption(const MozCallBarringOptions& aOptions, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); if (!IsValidCallBarringOptions(aOptions, false)) { nsresult rv = NotifyError(request, MOBILECONN_ERROR_INVALID_PARAMETER); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } // Fill in optional attributes. nsAutoString password; if (aOptions.mPassword.WasPassed()) { password = aOptions.mPassword.Value(); } else { password.SetIsVoid(true); } RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetCallBarring(aOptions.mProgram.Value().Value(), password, aOptions.mServiceClass.Value().Value(), requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetCallBarringOption(const MozCallBarringOptions& aOptions, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); if (!IsValidCallBarringOptions(aOptions, true)) { nsresult rv = NotifyError(request, MOBILECONN_ERROR_INVALID_PARAMETER); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetCallBarring(aOptions.mProgram.Value().Value(), aOptions.mEnabled.Value().Value(), aOptions.mPassword.Value(), aOptions.mServiceClass.Value().Value(), requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::ChangeCallBarringPassword(const MozCallBarringOptions& aOptions, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); if (!aOptions.mPin.WasPassed() || aOptions.mPin.Value().IsVoid() || !aOptions.mNewPin.WasPassed() || aOptions.mNewPin.Value().IsVoid() || !IsValidPassword(aOptions.mPin.Value()) || !IsValidPassword(aOptions.mNewPin.Value())) { nsresult rv = NotifyError(request, MOBILECONN_ERROR_INVALID_PASSWORD); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->ChangeCallBarringPassword(aOptions.mPin.Value(), aOptions.mNewPin.Value(), requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::GetCallWaitingOption(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetCallWaiting(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetCallWaitingOption(bool aEnabled, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetCallWaiting(aEnabled, nsIMobileConnection::ICC_SERVICE_CLASS_VOICE, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::GetCallingLineIdRestriction(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->GetCallingLineIdRestriction(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetCallingLineIdRestriction(uint16_t aMode, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetCallingLineIdRestriction(aMode, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::ExitEmergencyCbMode(ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->ExitEmergencyCbMode(requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed MobileConnection::SetRadioEnabled(bool aEnabled, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr request = new DOMRequest(GetOwner()); RefPtr requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetRadioEnabled(aEnabled, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } // nsIMobileConnectionListener NS_IMETHODIMP MobileConnection::NotifyVoiceChanged() { if (!CheckPermission("mobileconnection")) { return NS_OK; } UpdateVoice(); return DispatchTrustedEvent(NS_LITERAL_STRING("voicechange")); } NS_IMETHODIMP MobileConnection::NotifyDataChanged() { if (!CheckPermission("mobileconnection")) { return NS_OK; } UpdateData(); return DispatchTrustedEvent(NS_LITERAL_STRING("datachange")); } NS_IMETHODIMP MobileConnection::NotifyDataError(const nsAString& aMessage) { if (!CheckPermission("mobileconnection")) { return NS_OK; } DataErrorEventInit init; init.mBubbles = false; init.mCancelable = false; init.mMessage = aMessage; RefPtr event = DataErrorEvent::Constructor(this, NS_LITERAL_STRING("dataerror"), init); return DispatchTrustedEvent(event); } NS_IMETHODIMP MobileConnection::NotifyCFStateChanged(unsigned short aAction, unsigned short aReason, const nsAString& aNumber, unsigned short aSeconds, unsigned short aServiceClass) { if (!CheckPermission("mobileconnection")) { return NS_OK; } CFStateChangeEventInit init; init.mBubbles = false; init.mCancelable = false; init.mAction = aAction; init.mReason = aReason; init.mNumber = aNumber; init.mTimeSeconds = aSeconds; init.mServiceClass = aServiceClass; RefPtr event = CFStateChangeEvent::Constructor(this, NS_LITERAL_STRING("cfstatechange"), init); return DispatchTrustedEvent(event); } NS_IMETHODIMP MobileConnection::NotifyEmergencyCbModeChanged(bool aActive, uint32_t aTimeoutMs) { if (!CheckPermission("mobileconnection")) { return NS_OK; } MozEmergencyCbModeEventInit init; init.mBubbles = false; init.mCancelable = false; init.mActive = aActive; init.mTimeoutMs = aTimeoutMs; RefPtr event = MozEmergencyCbModeEvent::Constructor(this, NS_LITERAL_STRING("emergencycbmodechange"), init); return DispatchTrustedEvent(event); } NS_IMETHODIMP MobileConnection::NotifyOtaStatusChanged(const nsAString& aStatus) { if (!CheckPermission("mobileconnection")) { return NS_OK; } MozOtaStatusEventInit init; init.mBubbles = false; init.mCancelable = false; init.mStatus = aStatus; RefPtr event = MozOtaStatusEvent::Constructor(this, NS_LITERAL_STRING("otastatuschange"), init); return DispatchTrustedEvent(event); } NS_IMETHODIMP MobileConnection::NotifyRadioStateChanged() { if (!CheckPermission("mobileconnection")) { return NS_OK; } return DispatchTrustedEvent(NS_LITERAL_STRING("radiostatechange")); } NS_IMETHODIMP MobileConnection::NotifyClirModeChanged(uint32_t aMode) { if (!CheckPermission("mobileconnection")) { return NS_OK; } MozClirModeEventInit init; init.mBubbles = false; init.mCancelable = false; init.mMode = aMode; RefPtr event = MozClirModeEvent::Constructor(this, NS_LITERAL_STRING("clirmodechange"), init); return DispatchTrustedEvent(event); } NS_IMETHODIMP MobileConnection::NotifyLastKnownNetworkChanged() { return NS_OK; } NS_IMETHODIMP MobileConnection::NotifyLastKnownHomeNetworkChanged() { return NS_OK; } NS_IMETHODIMP MobileConnection::NotifyNetworkSelectionModeChanged() { return NS_OK; } NS_IMETHODIMP MobileConnection::NotifyDeviceIdentitiesChanged() { // To be supported when bug 1222870 is required in m-c. return NS_OK; } // nsIIccListener NS_IMETHODIMP MobileConnection::NotifyStkCommand(nsIStkProactiveCmd *aStkProactiveCmd) { return NS_OK; } NS_IMETHODIMP MobileConnection::NotifyStkSessionEnd() { return NS_OK; } NS_IMETHODIMP MobileConnection::NotifyCardStateChanged() { return NS_OK; } NS_IMETHODIMP MobileConnection::NotifyIccInfoChanged() { if (!CheckPermission("mobileconnection")) { return NS_OK; } if (!UpdateIccId()) { return NS_OK; } RefPtr asyncDispatcher = new AsyncEventDispatcher(this, NS_LITERAL_STRING("iccchange"), false); return asyncDispatcher->PostDOMEvent(); }