diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 1db0082d02a3..afc18afa2864 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -154,6 +154,11 @@ #include "mozilla/net/NeckoMessageUtils.h" #include "mozilla/RemoteSpellCheckEngineChild.h" +#ifdef MOZ_B2G_RIL +#include "mozilla/dom/mobileconnection/MobileConnectionChild.h" +using namespace mozilla::dom::mobileconnection; +#endif + using namespace base; using namespace mozilla; using namespace mozilla::docshell; @@ -1222,6 +1227,43 @@ ContentChild::DeallocPFileSystemRequestChild(PFileSystemRequestChild* aFileSyste return true; } +PMobileConnectionChild* +ContentChild::SendPMobileConnectionConstructor(PMobileConnectionChild* aActor, + const uint32_t& aClientId) +{ +#ifdef MOZ_B2G_RIL + // Add an extra ref for IPDL. Will be released in + // ContentChild::DeallocPMobileConnectionChild(). + static_cast(aActor)->AddRef(); + return PContentChild::SendPMobileConnectionConstructor(aActor, aClientId); +#else + MOZ_CRASH("No support for mobileconnection on this platform!");; +#endif +} + +PMobileConnectionChild* +ContentChild::AllocPMobileConnectionChild(const uint32_t& aClientId) +{ +#ifdef MOZ_B2G_RIL + NS_NOTREACHED("No one should be allocating PMobileConnectionChild actors"); + return nullptr; +#else + MOZ_CRASH("No support for mobileconnection on this platform!");; +#endif +} + +bool +ContentChild::DeallocPMobileConnectionChild(PMobileConnectionChild* aActor) +{ +#ifdef MOZ_B2G_RIL + // MobileConnectionChild is refcounted, must not be freed manually. + static_cast(aActor)->Release(); + return true; +#else + MOZ_CRASH("No support for mobileconnection on this platform!"); +#endif +} + PNeckoChild* ContentChild::AllocPNeckoChild() { diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index f08e10af33b6..6f529e7a4a80 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -191,6 +191,14 @@ public: virtual bool RecvPTestShellConstructor(PTestShellChild*) MOZ_OVERRIDE; jsipc::JavaScriptChild *GetCPOWManager(); + PMobileConnectionChild* + SendPMobileConnectionConstructor(PMobileConnectionChild* aActor, + const uint32_t& aClientId); + virtual PMobileConnectionChild* + AllocPMobileConnectionChild(const uint32_t& aClientId) MOZ_OVERRIDE; + virtual bool + DeallocPMobileConnectionChild(PMobileConnectionChild* aActor) MOZ_OVERRIDE; + virtual PNeckoChild* AllocPNeckoChild() MOZ_OVERRIDE; virtual bool DeallocPNeckoChild(PNeckoChild*) MOZ_OVERRIDE; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 95caaa327039..8f4af00bbf76 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -177,6 +177,11 @@ using namespace mozilla::system; #include "nsIIPCBackgroundChildCreateCallback.h" #endif +#ifdef MOZ_B2G_RIL +#include "mozilla/dom/mobileconnection/MobileConnectionParent.h" +using namespace mozilla::dom::mobileconnection; +#endif + #if defined(MOZ_CONTENT_SANDBOX) && defined(XP_LINUX) #include "mozilla/Sandbox.h" #endif @@ -3094,6 +3099,32 @@ ContentParent::DeallocPTestShellParent(PTestShellParent* shell) return true; } +PMobileConnectionParent* +ContentParent::AllocPMobileConnectionParent(const uint32_t& aClientId) +{ +#ifdef MOZ_B2G_RIL + nsRefPtr parent = new MobileConnectionParent(aClientId); + // We release this ref in DeallocPMobileConnectionParent(). + parent->AddRef(); + + return parent; +#else + MOZ_CRASH("No support for mobileconnection on this platform!"); +#endif +} + +bool +ContentParent::DeallocPMobileConnectionParent(PMobileConnectionParent* aActor) +{ +#ifdef MOZ_B2G_RIL + // MobileConnectionParent is refcounted, must not be freed manually. + static_cast(aActor)->Release(); + return true; +#else + MOZ_CRASH("No support for mobileconnection on this platform!"); +#endif +} + PNeckoParent* ContentParent::AllocPNeckoParent() { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 545f016b92d5..8ef5f160c523 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -463,6 +463,9 @@ private: virtual PTestShellParent* AllocPTestShellParent() MOZ_OVERRIDE; virtual bool DeallocPTestShellParent(PTestShellParent* shell) MOZ_OVERRIDE; + virtual PMobileConnectionParent* AllocPMobileConnectionParent(const uint32_t& aClientId) MOZ_OVERRIDE; + virtual bool DeallocPMobileConnectionParent(PMobileConnectionParent* aActor) MOZ_OVERRIDE; + virtual bool DeallocPNeckoParent(PNeckoParent* necko) MOZ_OVERRIDE; virtual PExternalHelperAppParent* AllocPExternalHelperAppParent( diff --git a/dom/mobileconnection/MobileConnectionCallback.cpp b/dom/mobileconnection/MobileConnectionCallback.cpp index a22a791b9709..bdebdbadcd42 100644 --- a/dom/mobileconnection/MobileConnectionCallback.cpp +++ b/dom/mobileconnection/MobileConnectionCallback.cpp @@ -22,6 +22,138 @@ MobileConnectionCallback::MobileConnectionCallback(nsPIDOMWindow* aWindow, { } +/** + * Notify Success for Send/CancelMmi. + */ +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage) +{ + MozMMIResult result; + result.mServiceCode.Assign(aServiceCode); + result.mStatusMessage.Assign(aStatusMessage); + + return NotifySendCancelMmiSuccess(result); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + JS::Handle aAdditionalInformation) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + RootedDictionary result(cx); + + result.mServiceCode.Assign(aServiceCode); + result.mStatusMessage.Assign(aStatusMessage); + result.mAdditionalInformation.Construct().SetAsObject() = &aAdditionalInformation.toObject(); + + return NotifySendCancelMmiSuccess(result); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + uint16_t aAdditionalInformation) +{ + MozMMIResult result; + result.mServiceCode.Assign(aServiceCode); + result.mStatusMessage.Assign(aStatusMessage); + result.mAdditionalInformation.Construct().SetAsUnsignedShort() = aAdditionalInformation; + + return NotifySendCancelMmiSuccess(result); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray& aAdditionalInformation) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted additionalInformation(cx); + + if (!ToJSValue(cx, aAdditionalInformation, &additionalInformation)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySendCancelMmiSuccess(aServiceCode, aStatusMessage, + additionalInformation); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray& aAdditionalInformation) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted additionalInformation(cx); + + if (!ToJSValue(cx, aAdditionalInformation, &additionalInformation)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySendCancelMmiSuccess(aServiceCode, aStatusMessage, + additionalInformation); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const MozMMIResult& aResult) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted jsResult(cx); + + if (!ToJSValue(cx, aResult, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +} + +/** + * Notify Success for GetCallForwarding. + */ +nsresult +MobileConnectionCallback::NotifyGetCallForwardingSuccess(const nsTArray& aResults) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted jsResult(cx); + + if (!ToJSValue(cx, aResults, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +} + /** * Notify Success. */ diff --git a/dom/mobileconnection/MobileConnectionCallback.h b/dom/mobileconnection/MobileConnectionCallback.h index 7e2f75f6169d..aa63dd306df8 100644 --- a/dom/mobileconnection/MobileConnectionCallback.h +++ b/dom/mobileconnection/MobileConnectionCallback.h @@ -6,6 +6,7 @@ #define mozilla_dom_MobileConnectionCallback_h #include "mozilla/dom/DOMRequest.h" +#include "mozilla/dom/MobileConnectionIPCSerializer.h" #include "nsCOMPtr.h" #include "nsIMobileConnectionService.h" @@ -30,6 +31,37 @@ public: MobileConnectionCallback(nsPIDOMWindow* aWindow, DOMRequest* aRequest); + /** + * Notify Success for Send/CancelMmi. + */ + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + JS::Handle aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + uint16_t aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray& aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray& aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const MozMMIResult& aResult); + + /** + * Notify Success for GetCallForwarding. + */ + nsresult + NotifyGetCallForwardingSuccess(const nsTArray& aResults); + private: ~MobileConnectionCallback() {} diff --git a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl index b5cdd7c99cbb..e43ad99a1864 100644 --- a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl +++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl @@ -119,7 +119,11 @@ interface nsIMobileConnectionListener : nsISupports void notifyNetworkSelectionModeChanged(); }; -[scriptable, builtinclass, uuid(eea91fcf-6bde-43be-aa01-d6cdfaad26e1)] +%{C++ +#define NO_ADDITIONAL_INFORMATION 0 +%} + +[scriptable, builtinclass, uuid(e9d7c247-34c6-42bf-875b-f99b19db394f)] interface nsIMobileConnectionCallback : nsISupports { /** @@ -152,6 +156,40 @@ interface nsIMobileConnectionCallback : nsISupports [optional] in DOMString message, [optional] in DOMString serviceCode, [optional] in unsigned short additionalInformation); + +%{C++ + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName) + { + return NotifyError(aName, EmptyString(), EmptyString(), + NO_ADDITIONAL_INFORMATION, 0 /* ARGC = 0 */); + } + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName, + const nsAString& aMessage) + { + return NotifyError(aName, aMessage, EmptyString(), NO_ADDITIONAL_INFORMATION, + 1 /* ARGC = 1 */); + } + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aServiceCode) + { + return NotifyError(aName, aMessage, aServiceCode, NO_ADDITIONAL_INFORMATION, + 2 /* ARGC = 2 */); + } + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aServiceCode, + uint16_t aAdditionInformation) + { + return NotifyError(aName, aMessage, aServiceCode, aAdditionInformation, + 3 /* ARGC = 3 */); + } +%} + }; %{C++ diff --git a/dom/mobileconnection/ipc/MobileConnectionChild.cpp b/dom/mobileconnection/ipc/MobileConnectionChild.cpp new file mode 100644 index 000000000000..4e7fc3ba2d8a --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp @@ -0,0 +1,471 @@ +/* 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 "MobileConnectionChild.h" + +#include "MobileConnectionCallback.h" +#include "mozilla/dom/MozMobileConnectionBinding.h" +#include "nsComponentManagerUtils.h" + +using namespace mozilla::dom; +using namespace mozilla::dom::mobileconnection; + +void +MobileConnectionChild::Init() +{ + nsIMobileConnectionInfo* rawVoice; + nsIMobileConnectionInfo* rawData; + nsTArray types; + + SendInit(&rawVoice, &rawData, &mLastNetwork, &mLastHomeNetwork, &mIccId, + &mNetworkSelectionMode, &mRadioState, &types); + + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr voice = dont_AddRef(rawVoice); + mVoice = new MobileConnectionInfo(nullptr); + mVoice->Update(voice); + + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr data = dont_AddRef(rawData); + mData = new MobileConnectionInfo(nullptr); + mData->Update(data); + + + // Initial SupportedNetworkTypes + nsresult rv; + mSupportedNetworkTypes = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); + + if (NS_FAILED(rv)) { + return; + } + + uint32_t arrayLen = types.Length(); + if (arrayLen == 0) { + mSupportedNetworkTypes->SetAsEmptyArray(); + } else { + // Note: The resulting nsIVariant dupes both the array and its elements. + const char16_t** array = reinterpret_cast + (NS_Alloc(arrayLen * sizeof(const char16_t***))); + if (array) { + for (uint32_t i = 0; i < arrayLen; ++i) { + array[i] = types[i].get(); + } + + mSupportedNetworkTypes->SetAsArray(nsIDataType::VTYPE_WCHAR_STR, + nullptr, + arrayLen, + reinterpret_cast(array)); + NS_Free(array); + } + } +} + +void +MobileConnectionChild::Shutdown() +{ + if (mLive) { + mLive = false; + Send__delete__(this); + } + + mListeners.Clear(); + mVoice = nullptr; + mData = nullptr; + mSupportedNetworkTypes = nullptr; +} + +void +MobileConnectionChild::RegisterListener(nsIMobileConnectionListener* aListener) +{ + if (!mListeners.Contains(aListener)) { + mListeners.AppendObject(aListener); + } +} + +void +MobileConnectionChild::UnregisterListener(nsIMobileConnectionListener* aListener) +{ + mListeners.RemoveObject(aListener); +} + +MobileConnectionInfo* +MobileConnectionChild::GetVoiceInfo() +{ + return mVoice; +} + +MobileConnectionInfo* +MobileConnectionChild::GetDataInfo() +{ + return mData; +} + +void +MobileConnectionChild::GetIccId(nsAString& aIccId) +{ + aIccId = mIccId; +} + +void +MobileConnectionChild::GetRadioState(nsAString& aRadioState) +{ + aRadioState = mRadioState; +} + +nsIVariant* +MobileConnectionChild::GetSupportedNetworkTypes() +{ + return mSupportedNetworkTypes; +} + +void +MobileConnectionChild::GetLastNetwork(nsAString& aNetwork) +{ + aNetwork = mLastNetwork; +} + +void +MobileConnectionChild::GetLastHomeNetwork(nsAString& aNetwork) +{ + aNetwork = mLastHomeNetwork; +} + +void +MobileConnectionChild::GetNetworkSelectionMode(nsAString& aMode) +{ + aMode = mNetworkSelectionMode; +} + +void +MobileConnectionChild::ActorDestroy(ActorDestroyReason why) +{ + mLive = false; +} + +PMobileConnectionRequestChild* +MobileConnectionChild::AllocPMobileConnectionRequestChild(const MobileConnectionRequest& request) +{ + MOZ_CRASH("Caller is supposed to manually construct a request!"); +} + +bool +MobileConnectionChild::DeallocPMobileConnectionRequestChild(PMobileConnectionRequestChild* aActor) +{ + delete aActor; + return true; +} + +bool +MobileConnectionChild::RecvNotifyVoiceInfoChanged(nsIMobileConnectionInfo* const& aInfo) +{ + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr voice = dont_AddRef(aInfo); + mVoice->Update(voice); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyVoiceChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyDataInfoChanged(nsIMobileConnectionInfo* const& aInfo) +{ + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr data = dont_AddRef(aInfo); + mData->Update(data); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyDataChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyUssdReceived(const nsString& aMessage, + const bool& aSessionEnd) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyUssdReceived(aMessage, aSessionEnd); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyDataError(const nsString& aMessage) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyDataError(aMessage); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyCFStateChanged(const bool& aSuccess, + const uint16_t& aAction, + const uint16_t& aReason, + const nsString& aNumber, + const uint16_t& aTimeSeconds, + const uint16_t& aServiceClass) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyCFStateChanged(aSuccess, aAction, aReason, aNumber, + aTimeSeconds, aServiceClass); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyEmergencyCbModeChanged(const bool& aActive, + const uint32_t& aTimeoutMs) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyEmergencyCbModeChanged(aActive, aTimeoutMs); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyOtaStatusChanged(const nsString& aStatus) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyOtaStatusChanged(aStatus); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyIccChanged(const nsString& aIccId) +{ + mIccId.Assign(aIccId); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyIccChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyRadioStateChanged(const nsString& aRadioState) +{ + mRadioState.Assign(aRadioState); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyRadioStateChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyClirModeChanged(const uint32_t& aMode) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyClirModeChanged(aMode); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyLastNetworkChanged(const nsString& aNetwork) +{ + mLastNetwork.Assign(aNetwork); + + return true; +} + +bool +MobileConnectionChild::RecvNotifyLastHomeNetworkChanged(const nsString& aNetwork) +{ + mLastHomeNetwork.Assign(aNetwork); + + return true; +} + +bool +MobileConnectionChild::RecvNotifyNetworkSelectionModeChanged(const nsString& aMode) +{ + mNetworkSelectionMode.Assign(aMode); + + return true; +} + +/****************************************************************************** + * MobileConnectionRequestChild + ******************************************************************************/ + +void +MobileConnectionRequestChild::ActorDestroy(ActorDestroyReason why) +{ + mRequestCallback = nullptr; +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccess& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifySuccess()); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessString& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifySuccessWithString(aReply.result())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessBoolean& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifySuccessWithBoolean(aReply.result())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessNetworks& aReply) +{ + uint32_t count = aReply.results().Length(); + nsTArray> results; + for (uint32_t i = 0; i < count; i++) { + // Use dont_AddRef here because these instances are already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr item = dont_AddRef(aReply.results()[i]); + results.AppendElement(item); + } + + return NS_SUCCEEDED(mRequestCallback->NotifyGetNetworksSuccess(count, + const_cast(aReply.results().Elements()))); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessMmi& aReply) +{ + nsAutoString serviceCode(aReply.serviceCode()); + nsAutoString statusMessage(aReply.statusMessage()); + AdditionalInformation info(aReply.additionalInformation()); + + nsRefPtr callback = static_cast(mRequestCallback.get()); + + + // Handle union types + switch (info.type()) { + case AdditionalInformation::Tvoid_t: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage)); + case AdditionalInformation::Tuint16_t: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage, + info.get_uint16_t())); + case AdditionalInformation::TArrayOfnsString: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage, + info.get_ArrayOfnsString())); + case AdditionalInformation::TArrayOfMozCallForwardingOptions: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage, + info.get_ArrayOfMozCallForwardingOptions())); + + default: + MOZ_CRASH("Received invalid type!"); + } + + return false; +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessCallForwarding& aReply) +{ + nsRefPtr callback = static_cast(mRequestCallback.get()); + return NS_SUCCEEDED(callback->NotifyGetCallForwardingSuccess(aReply.results())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessCallBarring& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifyGetCallBarringSuccess(aReply.program(), + aReply.enabled(), + aReply.serviceClass())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessClirStatus& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifyGetClirStatusSuccess(aReply.n(), + aReply.m())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplyError& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifyError(aReply.message())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplyErrorMmi& aReply) +{ + nsAutoString name(aReply.name()); + nsAutoString message(aReply.message()); + nsAutoString serviceCode(aReply.serviceCode()); + AdditionalInformation info(aReply.additionalInformation()); + + // Handle union types + switch (info.type()) { + case AdditionalInformation::Tuint16_t: + return NS_SUCCEEDED(mRequestCallback->NotifyError(name, + message, + serviceCode, + info.get_uint16_t())); + case AdditionalInformation::Tvoid_t: + default: + // If additionInfomation is not uint16_t, handle it as void_t. + return NS_SUCCEEDED(mRequestCallback->NotifyError(name, + message, + serviceCode)); + } + + return false; +} + +bool +MobileConnectionRequestChild::Recv__delete__(const MobileConnectionReply& aReply) +{ + MOZ_ASSERT(mRequestCallback); + + switch (aReply.type()) { + case MobileConnectionReply::TMobileConnectionReplySuccess: + return DoReply(aReply.get_MobileConnectionReplySuccess()); + case MobileConnectionReply::TMobileConnectionReplySuccessString: + return DoReply(aReply.get_MobileConnectionReplySuccessString()); + case MobileConnectionReply::TMobileConnectionReplySuccessBoolean: + return DoReply(aReply.get_MobileConnectionReplySuccessBoolean()); + case MobileConnectionReply::TMobileConnectionReplySuccessNetworks: + return DoReply(aReply.get_MobileConnectionReplySuccessNetworks()); + case MobileConnectionReply::TMobileConnectionReplySuccessMmi: + return DoReply(aReply.get_MobileConnectionReplySuccessMmi()); + case MobileConnectionReply::TMobileConnectionReplySuccessCallForwarding: + return DoReply(aReply.get_MobileConnectionReplySuccessCallForwarding()); + case MobileConnectionReply::TMobileConnectionReplySuccessCallBarring: + return DoReply(aReply.get_MobileConnectionReplySuccessCallBarring()); + case MobileConnectionReply::TMobileConnectionReplySuccessClirStatus: + return DoReply(aReply.get_MobileConnectionReplySuccessClirStatus()); + case MobileConnectionReply::TMobileConnectionReplyError: + return DoReply(aReply.get_MobileConnectionReplyError()); + case MobileConnectionReply::TMobileConnectionReplyErrorMmi: + return DoReply(aReply.get_MobileConnectionReplyErrorMmi()); + default: + MOZ_CRASH("Received invalid response type!"); + } + + return false; +} diff --git a/dom/mobileconnection/ipc/MobileConnectionChild.h b/dom/mobileconnection/ipc/MobileConnectionChild.h new file mode 100644 index 000000000000..f92118b7e584 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionChild.h @@ -0,0 +1,217 @@ +/* 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/. */ + +#ifndef mozilla_dom_mobileconnection_MobileConnectionChild_h +#define mozilla_dom_mobileconnection_MobileConnectionChild_h + +#include "mozilla/dom/MobileConnectionCallback.h" +#include "mozilla/dom/MobileConnectionInfo.h" +#include "mozilla/dom/PMobileConnectionChild.h" +#include "mozilla/dom/PMobileConnectionRequestChild.h" +#include "nsCOMArray.h" +#include "nsCOMPtr.h" +#include "nsIMobileConnectionService.h" +#include "nsIVariant.h" + +namespace mozilla { +namespace dom { +namespace mobileconnection { + +/** + * Child actor of PMobileConnection. The object is created by + * MobileConnectionIPCService and destroyed after MobileConnectionIPCService is + * shutdown. For multi-sim device, more than one instance will + * be created and each instance represents a sim slot. + */ +class MobileConnectionChild : public PMobileConnectionChild +{ + NS_INLINE_DECL_REFCOUNTING(MobileConnectionChild) + +public: + MobileConnectionChild() + : mLive(true) + { + MOZ_COUNT_CTOR(MobileConnectionChild); + } + + void + Init(); + + void + Shutdown(); + + void + RegisterListener(nsIMobileConnectionListener* aListener); + + void + UnregisterListener(nsIMobileConnectionListener* aListener); + + MobileConnectionInfo* + GetVoiceInfo(); + + MobileConnectionInfo* + GetDataInfo(); + + void + GetIccId(nsAString& aIccId); + + void + GetRadioState(nsAString& aRadioState); + + nsIVariant* + GetSupportedNetworkTypes(); + + void + GetLastNetwork(nsAString& aNetwork); + + void + GetLastHomeNetwork(nsAString& aNetwork); + + void + GetNetworkSelectionMode(nsAString& aMode); + +protected: + virtual + ~MobileConnectionChild() + { + MOZ_COUNT_DTOR(MobileConnectionChild); + Shutdown(); + } + + virtual void + ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; + + virtual PMobileConnectionRequestChild* + AllocPMobileConnectionRequestChild(const MobileConnectionRequest& request) MOZ_OVERRIDE; + + virtual bool + DeallocPMobileConnectionRequestChild(PMobileConnectionRequestChild* aActor) MOZ_OVERRIDE; + + virtual bool + RecvNotifyVoiceInfoChanged(nsIMobileConnectionInfo* const& aInfo) MOZ_OVERRIDE; + + virtual bool + RecvNotifyDataInfoChanged(nsIMobileConnectionInfo* const& aInfo) MOZ_OVERRIDE; + + virtual bool + RecvNotifyUssdReceived(const nsString& aMessage, + const bool& aSessionEnd) MOZ_OVERRIDE; + + virtual bool + RecvNotifyDataError(const nsString& aMessage) MOZ_OVERRIDE; + + virtual bool + RecvNotifyCFStateChanged(const bool& aSuccess, const uint16_t& aAction, + const uint16_t& aReason, const nsString& aNumber, + const uint16_t& aTimeSeconds, const uint16_t& aServiceClass) MOZ_OVERRIDE; + + virtual bool + RecvNotifyEmergencyCbModeChanged(const bool& aActive, + const uint32_t& aTimeoutMs) MOZ_OVERRIDE; + + virtual bool + RecvNotifyOtaStatusChanged(const nsString& aStatus) MOZ_OVERRIDE; + + virtual bool + RecvNotifyIccChanged(const nsString& aIccId) MOZ_OVERRIDE; + + virtual bool + RecvNotifyRadioStateChanged(const nsString& aRadioState) MOZ_OVERRIDE; + + virtual bool + RecvNotifyClirModeChanged(const uint32_t& aMode) MOZ_OVERRIDE; + + virtual bool + RecvNotifyLastNetworkChanged(const nsString& aNetwork) MOZ_OVERRIDE; + + virtual bool + RecvNotifyLastHomeNetworkChanged(const nsString& aNetwork) MOZ_OVERRIDE; + + virtual bool + RecvNotifyNetworkSelectionModeChanged(const nsString& aMode) MOZ_OVERRIDE; + +private: + bool mLive; + nsCOMArray mListeners; + nsCOMPtr mSupportedNetworkTypes; + nsRefPtr mVoice; + nsRefPtr mData; + nsString mIccId; + nsString mRadioState; + nsString mLastNetwork; + nsString mLastHomeNetwork; + nsString mNetworkSelectionMode; +}; + +/****************************************************************************** + * PMobileConnectionRequestChild + ******************************************************************************/ + +/** + * Child actor of PMobileConnectionRequest. The object is created when an + * asynchronous request is made and destroyed after receiving the response sent + * by parent actor. + */ +class MobileConnectionRequestChild : public PMobileConnectionRequestChild +{ +public: + MobileConnectionRequestChild(nsIMobileConnectionCallback* aRequestCallback) + : mRequestCallback(aRequestCallback) + { + MOZ_COUNT_CTOR(MobileConnectionRequestChild); + MOZ_ASSERT(mRequestCallback); + } + + bool + DoReply(const MobileConnectionReplySuccess& aReply); + + bool + DoReply(const MobileConnectionReplySuccessString& aReply); + + bool + DoReply(const MobileConnectionReplySuccessBoolean& aReply); + + bool + DoReply(const MobileConnectionReplySuccessNetworks& aReply); + + bool + DoReply(const MobileConnectionReplySuccessMmi& aReply); + + bool + DoReply(const MobileConnectionReplySuccessCallForwarding& aReply); + + bool + DoReply(const MobileConnectionReplySuccessCallBarring& aReply); + + bool + DoReply(const MobileConnectionReplySuccessClirStatus& aReply); + + bool + DoReply(const MobileConnectionReplyError& aReply); + + bool + DoReply(const MobileConnectionReplyErrorMmi& aReply); + +protected: + virtual + ~MobileConnectionRequestChild() + { + MOZ_COUNT_DTOR(MobileConnectionRequestChild); + } + + virtual void + ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; + + virtual bool + Recv__delete__(const MobileConnectionReply& aReply) MOZ_OVERRIDE; + +private: + nsCOMPtr mRequestCallback; +}; + +} // namespace mobileconnection +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_mobileconnection_MobileConnectionChild_h diff --git a/dom/mobileconnection/ipc/MobileConnectionParent.cpp b/dom/mobileconnection/ipc/MobileConnectionParent.cpp new file mode 100644 index 000000000000..0109e71fefa7 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp @@ -0,0 +1,729 @@ +/* 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 "MobileConnectionParent.h" + +#include "mozilla/AppProcessChecker.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/MobileConnectionIPCSerializer.h" +#include "mozilla/dom/MozMobileConnectionBinding.h" +#include "mozilla/dom/ToJSValue.h" +#include "nsIVariant.h" +#include "nsJSUtils.h" + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::dom::mobileconnection; + +MobileConnectionParent::MobileConnectionParent(uint32_t aClientId) + : mClientId(aClientId) + , mLive(true) +{ + MOZ_COUNT_CTOR(MobileConnectionParent); + + mService = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); + NS_ASSERTION(mService, "This shouldn't fail!"); + + if (mService) { + mService->RegisterListener(mClientId, this); + } +} + +void +MobileConnectionParent::ActorDestroy(ActorDestroyReason why) +{ + mLive = false; + if (mService) { + mService->UnregisterListener(mClientId, this); + mService = nullptr; + } +} + +bool +MobileConnectionParent::RecvPMobileConnectionRequestConstructor(PMobileConnectionRequestParent* aActor, + const MobileConnectionRequest& aRequest) +{ + MobileConnectionRequestParent* actor = static_cast(aActor); + + switch (aRequest.type()) { + case MobileConnectionRequest::TGetNetworksRequest: + return actor->DoRequest(aRequest.get_GetNetworksRequest()); + case MobileConnectionRequest::TSelectNetworkRequest: + return actor->DoRequest(aRequest.get_SelectNetworkRequest()); + case MobileConnectionRequest::TSelectNetworkAutoRequest: + return actor->DoRequest(aRequest.get_SelectNetworkAutoRequest()); + case MobileConnectionRequest::TSetPreferredNetworkTypeRequest: + return actor->DoRequest(aRequest.get_SetPreferredNetworkTypeRequest()); + case MobileConnectionRequest::TGetPreferredNetworkTypeRequest: + return actor->DoRequest(aRequest.get_GetPreferredNetworkTypeRequest()); + case MobileConnectionRequest::TSetRoamingPreferenceRequest: + return actor->DoRequest(aRequest.get_SetRoamingPreferenceRequest()); + case MobileConnectionRequest::TGetRoamingPreferenceRequest: + return actor->DoRequest(aRequest.get_GetRoamingPreferenceRequest()); + case MobileConnectionRequest::TSetVoicePrivacyModeRequest: + return actor->DoRequest(aRequest.get_SetVoicePrivacyModeRequest()); + case MobileConnectionRequest::TGetVoicePrivacyModeRequest: + return actor->DoRequest(aRequest.get_GetVoicePrivacyModeRequest()); + case MobileConnectionRequest::TSendMmiRequest: + return actor->DoRequest(aRequest.get_SendMmiRequest()); + case MobileConnectionRequest::TCancelMmiRequest: + return actor->DoRequest(aRequest.get_CancelMmiRequest()); + case MobileConnectionRequest::TSetCallForwardingRequest: + return actor->DoRequest(aRequest.get_SetCallForwardingRequest()); + case MobileConnectionRequest::TGetCallForwardingRequest: + return actor->DoRequest(aRequest.get_GetCallForwardingRequest()); + case MobileConnectionRequest::TSetCallBarringRequest: + return actor->DoRequest(aRequest.get_SetCallBarringRequest()); + case MobileConnectionRequest::TGetCallBarringRequest: + return actor->DoRequest(aRequest.get_GetCallBarringRequest()); + case MobileConnectionRequest::TChangeCallBarringPasswordRequest: + return actor->DoRequest(aRequest.get_ChangeCallBarringPasswordRequest()); + case MobileConnectionRequest::TSetCallWaitingRequest: + return actor->DoRequest(aRequest.get_SetCallWaitingRequest()); + case MobileConnectionRequest::TGetCallWaitingRequest: + return actor->DoRequest(aRequest.get_GetCallWaitingRequest()); + case MobileConnectionRequest::TSetCallingLineIdRestrictionRequest: + return actor->DoRequest(aRequest.get_SetCallingLineIdRestrictionRequest()); + case MobileConnectionRequest::TGetCallingLineIdRestrictionRequest: + return actor->DoRequest(aRequest.get_GetCallingLineIdRestrictionRequest()); + case MobileConnectionRequest::TExitEmergencyCbModeRequest: + return actor->DoRequest(aRequest.get_ExitEmergencyCbModeRequest()); + case MobileConnectionRequest::TSetRadioEnabledRequest: + return actor->DoRequest(aRequest.get_SetRadioEnabledRequest()); + default: + MOZ_CRASH("Received invalid request type!"); + } + + return false; +} + +PMobileConnectionRequestParent* +MobileConnectionParent::AllocPMobileConnectionRequestParent(const MobileConnectionRequest& request) +{ + if (!AssertAppProcessPermission(Manager(), "mobileconnection")) { + return nullptr; + } + + MobileConnectionRequestParent* actor = new MobileConnectionRequestParent(mClientId); + // Add an extra ref for IPDL. Will be released in + // MobileConnectionParent::DeallocPMobileConnectionRequestParent(). + actor->AddRef(); + return actor; +} + +bool +MobileConnectionParent::DeallocPMobileConnectionRequestParent(PMobileConnectionRequestParent* aActor) +{ + // MobileConnectionRequestParent is refcounted, must not be freed manually. + static_cast(aActor)->Release(); + return true; +} + +bool +MobileConnectionParent::RecvInit(nsMobileConnectionInfo* aVoice, + nsMobileConnectionInfo* aData, + nsString* aLastKnownNetwork, + nsString* aLastKnownHomeNetwork, + nsString* aIccId, + nsString* aNetworkSelectionMode, + nsString* aRadioState, + nsTArray* aSupportedNetworkTypes) +{ + NS_ENSURE_TRUE(mService, false); + + NS_ENSURE_SUCCESS(mService->GetVoiceConnectionInfo(mClientId, aVoice), false); + NS_ENSURE_SUCCESS(mService->GetDataConnectionInfo(mClientId, aData), false); + NS_ENSURE_SUCCESS(mService->GetLastKnownNetwork(mClientId, *aLastKnownNetwork), false); + NS_ENSURE_SUCCESS(mService->GetLastKnownHomeNetwork(mClientId, *aLastKnownHomeNetwork), false); + NS_ENSURE_SUCCESS(mService->GetIccId(mClientId, *aIccId), false); + NS_ENSURE_SUCCESS(mService->GetNetworkSelectionMode(mClientId, *aNetworkSelectionMode), false); + NS_ENSURE_SUCCESS(mService->GetRadioState(mClientId, *aRadioState), false); + + nsCOMPtr variant; + mService->GetSupportedNetworkTypes(mClientId, getter_AddRefs(variant)); + + uint16_t type; + nsIID iid; + uint32_t count; + void* data; + if (NS_FAILED(variant->GetAsArray(&type, &iid, &count, &data))) { + return false; + } + + // We expect the element type is wstring. + if (type == nsIDataType::VTYPE_WCHAR_STR) { + char16_t** rawArray = reinterpret_cast(data); + for (uint32_t i = 0; i < count; ++i) { + nsDependentString networkType(rawArray[i]); + aSupportedNetworkTypes->AppendElement(networkType); + } + } + NS_Free(data); + + return true; +} + +// nsIMobileConnectionListener + +NS_IMPL_ISUPPORTS(MobileConnectionParent, nsIMobileConnectionListener) + +NS_IMETHODIMP +MobileConnectionParent::NotifyVoiceChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsCOMPtr info; + rv = mService->GetVoiceConnectionInfo(mClientId, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + + // We release the ref after serializing process is finished in + // MobileConnectionIPCSerializer. + return SendNotifyVoiceInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyDataChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsCOMPtr info; + rv = mService->GetDataConnectionInfo(mClientId, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + + // We release the ref after serializing process is finished in + // MobileConnectionIPCSerializer. + return SendNotifyDataInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyUssdReceived(const nsAString& aMessage, + bool aSessionEnded) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyUssdReceived(nsAutoString(aMessage), aSessionEnded) + ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyDataError(const nsAString& aMessage) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyDataError(nsAutoString(aMessage)) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyCFStateChanged(bool aSuccess, + uint16_t aAction, + uint16_t aReason, + const nsAString &aNumber, + uint16_t aTimeSeconds, + uint16_t aServiceClass) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyCFStateChanged(aSuccess, aAction, aReason, + nsAutoString(aNumber), aTimeSeconds, + aServiceClass) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyEmergencyCbModeChanged(bool aActive, + uint32_t aTimeoutMs) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyEmergencyCbModeChanged(aActive, aTimeoutMs) + ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyOtaStatusChanged(const nsAString& aStatus) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyOtaStatusChanged(nsAutoString(aStatus)) + ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyIccChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsAutoString iccId; + mService->GetIccId(mClientId, iccId); + + return SendNotifyIccChanged(iccId) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyRadioStateChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString radioState; + rv = mService->GetRadioState(mClientId, radioState); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyRadioStateChanged(radioState) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyClirModeChanged(uint32_t aMode) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyClirModeChanged(aMode) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyLastKnownNetworkChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString network; + rv = mService->GetLastKnownNetwork(mClientId, network); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyLastNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyLastKnownHomeNetworkChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString network; + rv = mService->GetLastKnownHomeNetwork(mClientId, network); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyLastHomeNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyNetworkSelectionModeChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString mode; + rv = mService->GetNetworkSelectionMode(mClientId, mode); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyNetworkSelectionModeChanged(mode) ? NS_OK : NS_ERROR_FAILURE; +} + +/****************************************************************************** + * PMobileConnectionRequestParent + ******************************************************************************/ + +void +MobileConnectionRequestParent::ActorDestroy(ActorDestroyReason why) +{ + mLive = false; + mService = nullptr; +} + +bool +MobileConnectionRequestParent::DoRequest(const GetNetworksRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetNetworks(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SelectNetworkRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr network = dont_AddRef(aRequest.network()); + return NS_SUCCEEDED(mService->SelectNetwork(mClientId, network, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SelectNetworkAutoRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SelectNetworkAutomatically(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetPreferredNetworkTypeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetPreferredNetworkType(mClientId, aRequest.type(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetPreferredNetworkTypeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetPreferredNetworkType(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetRoamingPreferenceRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetRoamingPreference(mClientId, aRequest.mode(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetRoamingPreferenceRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetRoamingPreference(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetVoicePrivacyModeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetVoicePrivacyMode(mClientId, aRequest.enabled(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetVoicePrivacyModeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetVoicePrivacyMode(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SendMmiRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SendMMI(mClientId, aRequest.mmi(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const CancelMmiRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->CancelMMI(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallForwardingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->SetCallForwarding(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallForwardingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetCallForwarding(mClientId, aRequest.reason(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallBarringRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->SetCallBarring(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallBarringRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->GetCallBarring(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const ChangeCallBarringPasswordRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->ChangeCallBarringPassword(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallWaitingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetCallWaiting(mClientId, aRequest.enabled(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallWaitingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetCallWaiting(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallingLineIdRestrictionRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetCallingLineIdRestriction(mClientId, aRequest.mode(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallingLineIdRestrictionRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetCallingLineIdRestriction(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const ExitEmergencyCbModeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->ExitEmergencyCbMode(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetRadioEnabledRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetRadioEnabled(mClientId, aRequest.enabled(), this)); +} + +nsresult +MobileConnectionRequestParent::SendReply(const MobileConnectionReply& aReply) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE; +} + +// nsIMobileConnectionListener + +NS_IMPL_ISUPPORTS(MobileConnectionRequestParent, nsIMobileConnectionCallback); + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySuccess() +{ + return SendReply(MobileConnectionReplySuccess()); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySuccessWithString(const nsAString& aResult) +{ + return SendReply(MobileConnectionReplySuccessString(nsAutoString(aResult))); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySuccessWithBoolean(bool aResult) +{ + return SendReply(MobileConnectionReplySuccessBoolean(aResult)); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifyGetNetworksSuccess(uint32_t aCount, + nsIMobileNetworkInfo** aNetworks) +{ + nsTArray networks; + for (uint32_t i = 0; i < aCount; i++) { + nsCOMPtr network = aNetworks[i]; + // We release the ref after serializing process is finished in + // MobileConnectionIPCSerializer. + networks.AppendElement(network.forget().take()); + } + return SendReply(MobileConnectionReplySuccessNetworks(networks)); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySendCancelMmiSuccess(JS::Handle aResult) +{ + AutoSafeJSContext cx; + RootedDictionary result(cx); + + if (!result.Init(cx, aResult)) { + return NS_ERROR_TYPE_ERR; + } + + // No additionInformation passed + if (!result.mAdditionalInformation.WasPassed()) { + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(mozilla::void_t()))); + } + + OwningUnsignedShortOrObject& additionInformation = result.mAdditionalInformation.Value(); + + if (additionInformation.IsUnsignedShort()) { + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(uint16_t(additionInformation.GetAsUnsignedShort())))); + } + + if (additionInformation.IsObject()) { + uint32_t length; + JS::Rooted value(cx); + JS::Rooted object(cx, additionInformation.GetAsObject()); + + if (!JS_IsArrayObject(cx, object) || + !JS_GetArrayLength(cx, object, &length) || length <= 0 || + // Check first element to decide the format of array. + !JS_GetElement(cx, object, 0, &value)) { + return NS_ERROR_TYPE_ERR; + } + + // Check first element to decide the format of array. + if (value.isString()) { + // String[] + nsTArray infos; + for (uint32_t i = 0; i < length; i++) { + if (!JS_GetElement(cx, object, i, &value) || !value.isString()) { + return NS_ERROR_TYPE_ERR; + } + + nsAutoJSString str; + if (!str.init(cx, value.toString())) { + return NS_ERROR_FAILURE; + } + infos.AppendElement(str); + } + + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(infos))); + } else { + // IPC::MozCallForwardingOptions[] + nsTArray infos; + for (uint32_t i = 0; i < length; i++) { + IPC::MozCallForwardingOptions info; + if (!JS_GetElement(cx, object, i, &value) || !info.Init(cx, value)) { + return NS_ERROR_TYPE_ERR; + } + + infos.AppendElement(info); + } + + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(infos))); + } + } + + return NS_ERROR_TYPE_ERR; +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifyGetCallForwardingSuccess(JS::Handle aResults) +{ + uint32_t length; + AutoSafeJSContext cx; + JS::Rooted object(cx, &aResults.toObject()); + nsTArray results; + + if (!JS_IsArrayObject(cx, object) || + !JS_GetArrayLength(cx, object, &length)) { + return NS_ERROR_TYPE_ERR; + } + + for (uint32_t i = 0; i < length; i++) { + JS::Rooted entry(cx); + IPC::MozCallForwardingOptions info; + + if (!JS_GetElement(cx, object, i, &entry) || !info.Init(cx, entry)) { + return NS_ERROR_TYPE_ERR; + } + + results.AppendElement(info); + } + + return SendReply(MobileConnectionReplySuccessCallForwarding(results)); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifyGetCallBarringSuccess(uint16_t aProgram, + bool aEnabled, + uint16_t aServiceClass) +{ + return SendReply(MobileConnectionReplySuccessCallBarring(aProgram, aEnabled, + aServiceClass)); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifyGetClirStatusSuccess(uint16_t aN, + uint16_t aM) +{ + return SendReply(MobileConnectionReplySuccessClirStatus(aN, aM)); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifyError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aServiceCode, + uint16_t aInfo, + uint8_t aArgc) +{ + if (aArgc == 0) { + nsAutoString error(aName); + return SendReply(MobileConnectionReplyError(error)); + } + + nsAutoString name(aName); + nsAutoString message(aMessage); + nsAutoString serviceCode(aServiceCode); + + if (aArgc < 3) { + return SendReply(MobileConnectionReplyErrorMmi(name, message, serviceCode, + AdditionalInformation(mozilla::void_t()))); + } + + return SendReply(MobileConnectionReplyErrorMmi(name, message, serviceCode, + AdditionalInformation(aInfo))); +} diff --git a/dom/mobileconnection/ipc/MobileConnectionParent.h b/dom/mobileconnection/ipc/MobileConnectionParent.h new file mode 100644 index 000000000000..0c491cd5a88b --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionParent.h @@ -0,0 +1,180 @@ +/* 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/. */ + +#ifndef mozilla_dom_mobileconnection_MobileConnectionParent_h +#define mozilla_dom_mobileconnection_MobileConnectionParent_h + +#include "mozilla/dom/PMobileConnectionParent.h" +#include "mozilla/dom/PMobileConnectionRequestParent.h" +#include "nsIMobileConnectionInfo.h" +#include "nsIMobileConnectionService.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla { +namespace dom { +namespace mobileconnection { + +/** + * Parent actor of PMobileConnection. This object is created/destroyed along + * with child actor. + */ +class MobileConnectionParent : public PMobileConnectionParent + , public nsIMobileConnectionListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMOBILECONNECTIONLISTENER + + MobileConnectionParent(uint32_t aClientId); + +protected: + virtual + ~MobileConnectionParent() + { + MOZ_COUNT_DTOR(MobileConnectionParent); + } + + virtual void + ActorDestroy(ActorDestroyReason why); + + virtual bool + RecvPMobileConnectionRequestConstructor(PMobileConnectionRequestParent* aActor, + const MobileConnectionRequest& aRequest) MOZ_OVERRIDE; + + virtual PMobileConnectionRequestParent* + AllocPMobileConnectionRequestParent(const MobileConnectionRequest& request) MOZ_OVERRIDE; + + virtual bool + DeallocPMobileConnectionRequestParent(PMobileConnectionRequestParent* aActor) MOZ_OVERRIDE; + + virtual bool + RecvInit(nsMobileConnectionInfo* aVoice, nsMobileConnectionInfo* aData, + nsString* aLastKnownNetwork, nsString* aLastKnownHomeNetwork, + nsString* aIccId, nsString* aNetworkSelectionMode, + nsString* aRadioState, nsTArray* aSupportedNetworkTypes) MOZ_OVERRIDE; + +private: + uint32_t mClientId; + bool mLive; + nsCOMPtr mService; +}; + +/****************************************************************************** + * PMobileConnectionRequestParent + ******************************************************************************/ + +/** + * Parent actor of PMobileConnectionRequestParent. The object is created along + * with child actor and destroyed after the callback function of + * nsIMobileConnectionCallback is called. Child actor might be destroyed before + * any callback is triggered. So we use mLive to maintain the status of child + * actor in order to present sending data to a dead one. + */ +class MobileConnectionRequestParent : public PMobileConnectionRequestParent + , public nsIMobileConnectionCallback +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMOBILECONNECTIONCALLBACK + + MobileConnectionRequestParent(uint32_t aClientId) + : mClientId(aClientId) + , mLive(true) + { + MOZ_COUNT_CTOR(MobileConnectionRequestParent); + + mService = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); + NS_ASSERTION(mService, "This shouldn't fail!"); + } + + bool + DoRequest(const GetNetworksRequest& aRequest); + + bool + DoRequest(const SelectNetworkRequest& aRequest); + + bool + DoRequest(const SelectNetworkAutoRequest& aRequest); + + bool + DoRequest(const SetPreferredNetworkTypeRequest& aRequest); + + bool + DoRequest(const GetPreferredNetworkTypeRequest& aRequest); + + bool + DoRequest(const SetRoamingPreferenceRequest& aRequest); + + bool + DoRequest(const GetRoamingPreferenceRequest& aRequest); + + bool + DoRequest(const SetVoicePrivacyModeRequest& aRequest); + + bool + DoRequest(const GetVoicePrivacyModeRequest& aRequest); + + bool + DoRequest(const SendMmiRequest& aRequest); + + bool + DoRequest(const CancelMmiRequest& aRequest); + + bool + DoRequest(const SetCallForwardingRequest& aRequest); + + bool + DoRequest(const GetCallForwardingRequest& aRequest); + + bool + DoRequest(const SetCallBarringRequest& aRequest); + + bool + DoRequest(const GetCallBarringRequest& aRequest); + + bool + DoRequest(const ChangeCallBarringPasswordRequest& aRequest); + + bool + DoRequest(const SetCallWaitingRequest& aRequest); + + bool + DoRequest(const GetCallWaitingRequest& aRequest); + + bool + DoRequest(const SetCallingLineIdRestrictionRequest& aRequest); + + bool + DoRequest(const GetCallingLineIdRestrictionRequest& aRequest); + + bool + DoRequest(const ExitEmergencyCbModeRequest& aRequest); + + bool + DoRequest(const SetRadioEnabledRequest& aRequest); + +protected: + virtual + ~MobileConnectionRequestParent() + { + MOZ_COUNT_DTOR(MobileConnectionRequestParent); + } + + virtual void + ActorDestroy(ActorDestroyReason why); + + nsresult + SendReply(const MobileConnectionReply& aReply); + +private: + uint32_t mClientId; + bool mLive; + nsCOMPtr mService; +}; + +} // namespace mobileconnection +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_mobileconnection_MobileConnectionParent_h \ No newline at end of file diff --git a/dom/mobileconnection/moz.build b/dom/mobileconnection/moz.build index 9d06facc3419..c67f27861c11 100644 --- a/dom/mobileconnection/moz.build +++ b/dom/mobileconnection/moz.build @@ -19,8 +19,15 @@ EXPORTS.mozilla.dom += [ 'MobileNetworkInfo.h', ] +EXPORTS.mozilla.dom.mobileconnection += [ + 'ipc/MobileConnectionChild.h', + 'ipc/MobileConnectionParent.h', +] + SOURCES += [ 'DOMMMIError.cpp', + 'ipc/MobileConnectionChild.cpp', + 'ipc/MobileConnectionParent.cpp', 'MobileCellInfo.cpp', 'MobileConnection.cpp', 'MobileConnectionArray.cpp',