Bug 903403 - [sms][mms] Make getSegmentInfoForText() Asynchronous to Improve Typing Performance. r=vicamo, sr=mounir
authorGene Lian <clian@mozilla.com>
Fri, 09 Aug 2013 21:25:53 +0800
changeset 158442 9dc1fcc1964eb4fd71e562148cdcf78aa1c6211d
parent 158441 e92a979238640641475862420bac820117d493e2
child 158443 3cb18fbc1eff5248c0399858e0b0b55faa5f120c
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvicamo, mounir
bugs903403
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 903403 - [sms][mms] Make getSegmentInfoForText() Asynchronous to Improve Typing Performance. r=vicamo, sr=mounir
dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl
dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl
dom/mobilemessage/interfaces/nsISmsService.idl
dom/mobilemessage/src/MobileMessageCallback.cpp
dom/mobilemessage/src/MobileMessageCallback.h
dom/mobilemessage/src/MobileMessageManager.cpp
dom/mobilemessage/src/SmsSegmentInfo.cpp
dom/mobilemessage/src/SmsSegmentInfo.h
dom/mobilemessage/src/android/SmsService.cpp
dom/mobilemessage/src/fallback/SmsService.cpp
dom/mobilemessage/src/gonk/SmsService.cpp
dom/mobilemessage/src/ipc/PSms.ipdl
dom/mobilemessage/src/ipc/PSmsRequest.ipdl
dom/mobilemessage/src/ipc/SmsChild.cpp
dom/mobilemessage/src/ipc/SmsIPCService.cpp
dom/mobilemessage/src/ipc/SmsParent.cpp
dom/mobilemessage/src/ipc/SmsParent.h
dom/mobilemessage/tests/marionette/test_getsegmentinfofortext.js
dom/mobilemessage/tests/marionette/test_segment_info.js
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/nsIRadioInterfaceLayer.idl
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
--- a/dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl
+++ b/dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl
@@ -6,20 +6,20 @@
 
 interface nsIDOMEventListener;
 interface nsIDOMMozSmsFilter;
 interface nsIDOMMozSmsSegmentInfo;
 interface nsIDOMDOMCursor;
 interface nsIDOMDOMRequest;
 interface nsIDOMBlob;
 
-[scriptable, builtinclass, uuid(efff5276-0f3f-4137-9b16-66e894400e01)]
+[scriptable, builtinclass, uuid(3f81dcbc-00cf-11e3-ae66-538115636543)]
 interface nsIDOMMozMobileMessageManager : nsIDOMEventTarget
 {
-  nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
+  nsIDOMDOMRequest getSegmentInfoForText(in DOMString text);
 
   // The first parameter can be either a DOMString (only one number) or an array
   // of DOMStrings.
   // The method returns a DOMRequest object if one number has been passed.
   // An array of DOMRequest objects otherwise.
   jsval send(in jsval number, in DOMString message);
 
   nsIDOMDOMRequest sendMMS(in jsval parameters /* MmsParameters */);
--- a/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl
+++ b/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl
@@ -1,24 +1,25 @@
 /* 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 "nsISupports.idl"
+#include "nsIDOMSmsSegmentInfo.idl"
 
 dictionary SmsThreadListItem
 {
   unsigned long long id;
   DOMString senderOrReceiver;
   unsigned long long timestamp;
   DOMString body;
   unsigned long long unreadCount;
 };
 
-[scriptable, uuid(ea5fb581-bee7-40a6-b2dc-c98b99a2dc49)]
+[scriptable, uuid(399125a8-00d2-11e3-8d12-3fba4465c097)]
 interface nsIMobileMessageCallback : nsISupports
 {
   /**
    * All SMS related errors.
    * Make sure to keep this list in sync with the list in:
    * embedding/android/GeckoSmsManager.java
    */
   const unsigned short SUCCESS_NO_ERROR          = 0;
@@ -43,9 +44,12 @@ interface nsIMobileMessageCallback : nsI
   void notifyGetMessageFailed(in long error);
 
   void notifyMessageDeleted([array, size_is(count)] in boolean deleted,
                             in uint32_t count);
   void notifyDeleteMessageFailed(in long error);
 
   void notifyMessageMarkedRead(in boolean read);
   void notifyMarkMessageReadFailed(in long error);
+
+  void notifySegmentInfoForTextGot(in nsIDOMMozSmsSegmentInfo info);
+  void notifyGetSegmentInfoForTextFailed(in long error);
 };
--- a/dom/mobilemessage/interfaces/nsISmsService.idl
+++ b/dom/mobilemessage/interfaces/nsISmsService.idl
@@ -8,22 +8,23 @@ interface nsIDOMMozSmsMessage;
 interface nsIDOMMozSmsSegmentInfo;
 interface nsIMobileMessageCallback;
 
 %{C++
 #define SMS_SERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
 #define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
 %}
 
-[scriptable, builtinclass, uuid(f0d5d11b-0326-4cb1-bb76-a3f912212287)]
+[scriptable, builtinclass, uuid(0f3f75ec-00dd-11e3-87ac-0b1d5c79afdf)]
 interface nsISmsService : nsISupports
 {
   boolean hasSupport();
 
-  nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
+  void getSegmentInfoForText(in DOMString text,
+                             in nsIMobileMessageCallback request);
 
   void send(in DOMString number,
             in DOMString message,
             in boolean silent,
             in nsIMobileMessageCallback request);
 
   boolean isSilentNumber(in DOMString number);
   void addSilentNumber(in DOMString number);
--- a/dom/mobilemessage/src/MobileMessageCallback.cpp
+++ b/dom/mobilemessage/src/MobileMessageCallback.cpp
@@ -3,16 +3,17 @@
  * 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 "MobileMessageCallback.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsIDOMMozSmsMessage.h"
 #include "nsIDOMMozMmsMessage.h"
+#include "nsIDOMSmsSegmentInfo.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsPIDOMWindow.h"
 #include "MmsMessage.h"
 #include "jsapi.h"
 #include "xpcpublic.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArrayHelpers.h"
 
@@ -34,24 +35,32 @@ MobileMessageCallback::MobileMessageCall
 }
 
 MobileMessageCallback::~MobileMessageCallback()
 {
 }
 
 
 nsresult
-MobileMessageCallback::NotifySuccess(JS::Handle<JS::Value> aResult)
+MobileMessageCallback::NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync)
 {
+  if (aAsync) {
+    nsCOMPtr<nsIDOMRequestService> rs =
+      do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
+    NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
+
+    return rs->FireSuccessAsync(mDOMRequest, aResult);
+  }
+
   mDOMRequest->FireSuccess(aResult);
   return NS_OK;
 }
 
 nsresult
-MobileMessageCallback::NotifySuccess(nsISupports *aMessage)
+MobileMessageCallback::NotifySuccess(nsISupports *aMessage, bool aAsync)
 {
   nsresult rv;
   nsIScriptContext* scriptContext = mDOMRequest->GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
 
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
@@ -61,48 +70,58 @@ MobileMessageCallback::NotifySuccess(nsI
 
   JSAutoCompartment ac(cx, global);
 
   JS::Rooted<JS::Value> wrappedMessage(cx);
   rv = nsContentUtils::WrapNative(cx, global, aMessage,
                                   wrappedMessage.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return NotifySuccess(wrappedMessage);
+  return NotifySuccess(wrappedMessage, aAsync);
 }
 
 nsresult
-MobileMessageCallback::NotifyError(int32_t aError)
+MobileMessageCallback::NotifyError(int32_t aError, bool aAsync)
 {
+  nsAutoString errorStr;
   switch (aError) {
     case nsIMobileMessageCallback::NO_SIGNAL_ERROR:
-      mDOMRequest->FireError(NS_LITERAL_STRING("NoSignalError"));
+      errorStr = NS_LITERAL_STRING("NoSignalError");
       break;
     case nsIMobileMessageCallback::NOT_FOUND_ERROR:
-      mDOMRequest->FireError(NS_LITERAL_STRING("NotFoundError"));
+      errorStr = NS_LITERAL_STRING("NotFoundError");
       break;
     case nsIMobileMessageCallback::UNKNOWN_ERROR:
-      mDOMRequest->FireError(NS_LITERAL_STRING("UnknownError"));
+      errorStr = NS_LITERAL_STRING("UnknownError");
       break;
     case nsIMobileMessageCallback::INTERNAL_ERROR:
-      mDOMRequest->FireError(NS_LITERAL_STRING("InternalError"));
+      errorStr = NS_LITERAL_STRING("InternalError");
       break;
     case nsIMobileMessageCallback::NO_SIM_CARD_ERROR:
-      mDOMRequest->FireError(NS_LITERAL_STRING("NoSimCardError"));
+      errorStr = NS_LITERAL_STRING("NoSimCardError");
       break;
     case nsIMobileMessageCallback::RADIO_DISABLED_ERROR:
-      mDOMRequest->FireError(NS_LITERAL_STRING("RadioDisabledError"));
+      errorStr = NS_LITERAL_STRING("RadioDisabledError");
       break;
     case nsIMobileMessageCallback::INVALID_ADDRESS_ERROR:
-      mDOMRequest->FireError(NS_LITERAL_STRING("InvalidAddressError"));
+      errorStr = NS_LITERAL_STRING("InvalidAddressError");
       break;
     default: // SUCCESS_NO_ERROR is handled above.
       MOZ_CRASH("Should never get here!");
   }
 
+  if (aAsync) {
+    nsCOMPtr<nsIDOMRequestService> rs =
+      do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
+    NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
+
+    return rs->FireErrorAsync(mDOMRequest, errorStr);
+  }
+
+  mDOMRequest->FireError(errorStr);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileMessageCallback::NotifyMessageSent(nsISupports *aMessage)
 {
   return NotifySuccess(aMessage);
 }
@@ -168,11 +187,23 @@ MobileMessageCallback::NotifyMessageMark
 }
 
 NS_IMETHODIMP
 MobileMessageCallback::NotifyMarkMessageReadFailed(int32_t aError)
 {
   return NotifyError(aError);
 }
 
+NS_IMETHODIMP
+MobileMessageCallback::NotifySegmentInfoForTextGot(nsIDOMMozSmsSegmentInfo *aInfo)
+{
+  return NotifySuccess(aInfo, true);
+}
+
+NS_IMETHODIMP
+MobileMessageCallback::NotifyGetSegmentInfoForTextFailed(int32_t aError)
+{
+  return NotifyError(aError, true);
+}
+
 } // namesapce mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/src/MobileMessageCallback.h
+++ b/dom/mobilemessage/src/MobileMessageCallback.h
@@ -24,18 +24,18 @@ public:
 
   MobileMessageCallback(DOMRequest* aDOMRequest);
 
 private:
   ~MobileMessageCallback();
 
   nsRefPtr<DOMRequest> mDOMRequest;
 
-  nsresult NotifySuccess(JS::Handle<JS::Value> aResult);
-  nsresult NotifySuccess(nsISupports *aMessage);
-  nsresult NotifyError(int32_t aError);
+  nsresult NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync = false);
+  nsresult NotifySuccess(nsISupports *aMessage, bool aAsync = false);
+  nsresult NotifyError(int32_t aError, bool aAsync = false);
 };
 
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobilemessage_MobileMessageCallback_h
--- a/dom/mobilemessage/src/MobileMessageManager.cpp
+++ b/dom/mobilemessage/src/MobileMessageManager.cpp
@@ -96,22 +96,29 @@ MobileMessageManager::Shutdown()
   obs->RemoveObserver(this, kSmsSentObserverTopic);
   obs->RemoveObserver(this, kSmsFailedObserverTopic);
   obs->RemoveObserver(this, kSmsDeliverySuccessObserverTopic);
   obs->RemoveObserver(this, kSmsDeliveryErrorObserverTopic);
 }
 
 NS_IMETHODIMP
 MobileMessageManager::GetSegmentInfoForText(const nsAString& aText,
-                                            nsIDOMMozSmsSegmentInfo** aResult)
+                                            nsIDOMDOMRequest** aRequest)
 {
   nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, NS_ERROR_FAILURE);
 
-  return smsService->GetSegmentInfoForText(aText, aResult);
+  nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
+  nsCOMPtr<nsIMobileMessageCallback> msgCallback =
+    new MobileMessageCallback(request);
+  nsresult rv = smsService->GetSegmentInfoForText(aText, msgCallback);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  request.forget(aRequest);
+  return NS_OK;
 }
 
 nsresult
 MobileMessageManager::Send(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
                            JS::Handle<JSString*> aNumber,
                            const nsAString& aMessage, JS::Value* aRequest)
 {
   nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
--- a/dom/mobilemessage/src/SmsSegmentInfo.cpp
+++ b/dom/mobilemessage/src/SmsSegmentInfo.cpp
@@ -50,10 +50,16 @@ SmsSegmentInfo::GetCharsPerSegment(int32
 
 NS_IMETHODIMP
 SmsSegmentInfo::GetCharsAvailableInLastSegment(int32_t* aCharsAvailableInLastSegment)
 {
   *aCharsAvailableInLastSegment = mData.charsAvailableInLastSegment();
   return NS_OK;
 }
 
+const SmsSegmentInfoData&
+SmsSegmentInfo::GetData() const
+{
+  return mData;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/src/SmsSegmentInfo.h
+++ b/dom/mobilemessage/src/SmsSegmentInfo.h
@@ -17,18 +17,21 @@ class SmsSegmentInfo MOZ_FINAL : public 
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZSMSSEGMENTINFO
 
   SmsSegmentInfo(int32_t aSegments,
                  int32_t aCharsPerSegment,
                  int32_t aCharsAvailableInLastSegment);
+
   SmsSegmentInfo(const mobilemessage::SmsSegmentInfoData& aData);
 
+  const mobilemessage::SmsSegmentInfoData& GetData() const;
+
 private:
   mobilemessage::SmsSegmentInfoData mData;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobilemessage_SmsSegmentInfo_h
--- a/dom/mobilemessage/src/android/SmsService.cpp
+++ b/dom/mobilemessage/src/android/SmsService.cpp
@@ -18,29 +18,26 @@ NS_IMPL_ISUPPORTS1(SmsService, nsISmsSer
 NS_IMETHODIMP
 SmsService::HasSupport(bool* aHasSupport)
 {
   *aHasSupport = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsService::GetSegmentInfoForText(const nsAString & aText,
-                                  nsIDOMMozSmsSegmentInfo** aResult)
+SmsService::GetSegmentInfoForText(const nsAString& aText,
+                                  nsIMobileMessageCallback* aRequest)
 {
   if (!AndroidBridge::Bridge()) {
     return NS_ERROR_FAILURE;
   }
 
-  SmsSegmentInfoData data;
-  nsresult rv = AndroidBridge::Bridge()->GetSegmentInfoForText(aText, &data);
+  nsresult rv = AndroidBridge::Bridge()->GetSegmentInfoForText(aText, aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
-  info.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsService::Send(const nsAString& aNumber,
                  const nsAString& aMessage,
                  const bool       aSilent,
                  nsIMobileMessageCallback* aRequest)
--- a/dom/mobilemessage/src/fallback/SmsService.cpp
+++ b/dom/mobilemessage/src/fallback/SmsService.cpp
@@ -17,18 +17,18 @@ NS_IMPL_ISUPPORTS1(SmsService, nsISmsSer
 NS_IMETHODIMP
 SmsService::HasSupport(bool* aHasSupport)
 {
   *aHasSupport = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsService::GetSegmentInfoForText(const nsAString & aText,
-                                  nsIDOMMozSmsSegmentInfo** aResult)
+SmsService::GetSegmentInfoForText(const nsAString& aText,
+                                  nsIMobileMessageCallback* aRequest)
 {
   NS_ERROR("We should not be here!");
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SmsService::Send(const nsAString& aNumber,
                  const nsAString& aMessage,
--- a/dom/mobilemessage/src/gonk/SmsService.cpp
+++ b/dom/mobilemessage/src/gonk/SmsService.cpp
@@ -26,22 +26,22 @@ SmsService::SmsService()
 NS_IMETHODIMP
 SmsService::HasSupport(bool* aHasSupport)
 {
   *aHasSupport = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsService::GetSegmentInfoForText(const nsAString & aText,
-                                  nsIDOMMozSmsSegmentInfo** aResult)
+SmsService::GetSegmentInfoForText(const nsAString& aText,
+                                  nsIMobileMessageCallback* aRequest)
 {
   NS_ENSURE_TRUE(mRadioInterface, NS_ERROR_FAILURE);
 
-  return mRadioInterface->GetSegmentInfoForText(aText, aResult);
+  return mRadioInterface->GetSegmentInfoForText(aText, aRequest);
 }
 
 NS_IMETHODIMP
 SmsService::Send(const nsAString& aNumber,
                  const nsAString& aMessage,
                  const bool       aSilent,
                  nsIMobileMessageCallback* aRequest)
 {
--- a/dom/mobilemessage/src/ipc/PSms.ipdl
+++ b/dom/mobilemessage/src/ipc/PSms.ipdl
@@ -57,27 +57,33 @@ struct CreateMessageCursorRequest
 };
 
 struct MarkMessageReadRequest
 {
   int32_t messageId;
   bool value;
 };
 
+struct GetSegmentInfoForTextRequest
+{
+  nsString text;
+};
+
 struct CreateThreadCursorRequest
 {
 };
 
 union IPCSmsRequest
 {
   SendMessageRequest;
   RetrieveMessageRequest;
   GetMessageRequest;
   DeleteMessageRequest;
   MarkMessageReadRequest;
+  GetSegmentInfoForTextRequest;
 };
 
 union IPCMobileMessageCursor
 {
   CreateMessageCursorRequest;
   CreateThreadCursorRequest;
 };
 
@@ -117,18 +123,15 @@ parent:
   /**
    * Sent when the child makes an asynchronous cursor to the parent.
    */
   PMobileMessageCursor(IPCMobileMessageCursor request);
 
   sync HasSupport()
       returns (bool aHasSupport);
 
-  sync GetSegmentInfoForText(nsString aText)
-      returns (SmsSegmentInfoData aResult);
-
   AddSilentNumber(nsString aNumber);
   RemoveSilentNumber(nsString aNumber);
 };
 
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/src/ipc/PSmsRequest.ipdl
+++ b/dom/mobilemessage/src/ipc/PSmsRequest.ipdl
@@ -61,23 +61,35 @@ struct ReplyMarkeMessageRead
   bool read;
 };
 
 struct ReplyMarkeMessageReadFail
 {
   int32_t error;
 };
 
+struct ReplyGetSegmentInfoForText
+{
+  SmsSegmentInfoData infoData;
+};
+
+struct ReplyGetSegmentInfoForTextFail
+{
+  int32_t error;
+};
+
 union MessageReply
 {
   ReplyMessageSend;
   ReplyMessageSendFail;
   ReplyGetMessage;
   ReplyGetMessageFail;
   ReplyMessageDelete;
   ReplyMessageDeleteFail;
   ReplyMarkeMessageRead;
   ReplyMarkeMessageReadFail;
+  ReplyGetSegmentInfoForText;
+  ReplyGetSegmentInfoForTextFail;
 };
 
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/src/ipc/SmsChild.cpp
+++ b/dom/mobilemessage/src/ipc/SmsChild.cpp
@@ -1,15 +1,16 @@
 /* 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 "SmsChild.h"
 #include "SmsMessage.h"
 #include "MmsMessage.h"
+#include "SmsSegmentInfo.h"
 #include "Constants.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/ContentChild.h"
 #include "MobileMessageThread.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -17,17 +18,17 @@ using namespace mozilla::dom::mobilemess
 
 namespace {
 
 already_AddRefed<nsISupports>
 CreateMessageFromMessageData(const MobileMessageData& aData)
 {
   nsCOMPtr<nsISupports> message;
 
-  switch(aData. type()) {
+  switch(aData.type()) {
     case MobileMessageData::TMmsMessageData:
       message = new MmsMessage(aData.get_MmsMessageData());
       break;
     case MobileMessageData::TSmsMessageData:
       message = new SmsMessage(aData.get_SmsMessageData());
       break;
     default:
       MOZ_CRASH("Unexpected type of MobileMessageData");
@@ -198,16 +199,27 @@ SmsRequestChild::Recv__delete__(const Me
       mReplyRequest->NotifyDeleteMessageFailed(aReply.get_ReplyMessageDeleteFail().error());
       break;
     case MessageReply::TReplyMarkeMessageRead:
       mReplyRequest->NotifyMessageMarkedRead(aReply.get_ReplyMarkeMessageRead().read());
       break;
     case MessageReply::TReplyMarkeMessageReadFail:
       mReplyRequest->NotifyMarkMessageReadFailed(aReply.get_ReplyMarkeMessageReadFail().error());
       break;
+    case MessageReply::TReplyGetSegmentInfoForText: {
+        const SmsSegmentInfoData& data =
+          aReply.get_ReplyGetSegmentInfoForText().infoData();
+        nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
+        mReplyRequest->NotifySegmentInfoForTextGot(info);
+      }
+      break;
+    case MessageReply::TReplyGetSegmentInfoForTextFail:
+      mReplyRequest->NotifyGetSegmentInfoForTextFailed(
+        aReply.get_ReplyGetSegmentInfoForTextFail().error());
+      break;
     default:
       MOZ_CRASH("Received invalid response parameters!");
   }
 
   return true;
 }
 
 /*******************************************************************************
--- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp
@@ -91,29 +91,21 @@ SmsIPCService::HasSupport(bool* aHasSupp
   NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE);
 
   smsChild->SendHasSupport(aHasSupport);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsIPCService::GetSegmentInfoForText(const nsAString & aText,
-                                     nsIDOMMozSmsSegmentInfo** aResult)
+SmsIPCService::GetSegmentInfoForText(const nsAString& aText,
+                                     nsIMobileMessageCallback* aRequest)
 {
-  PSmsChild* smsChild = GetSmsChild();
-  NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE);
-
-  SmsSegmentInfoData data;
-  bool ok = smsChild->SendGetSegmentInfoForText(nsString(aText), &data);
-  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
-  info.forget(aResult);
-  return NS_OK;
+  return SendRequest(GetSegmentInfoForTextRequest(nsString(aText)),
+                                                  aRequest);
 }
 
 NS_IMETHODIMP
 SmsIPCService::Send(const nsAString& aNumber,
                     const nsAString& aMessage,
                     const bool aSilent,
                     nsIMobileMessageCallback* aRequest)
 {
--- a/dom/mobilemessage/src/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/src/ipc/SmsParent.cpp
@@ -307,45 +307,16 @@ SmsParent::RecvHasSupport(bool* aHasSupp
   nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, true);
 
   smsService->HasSupport(aHasSupport);
   return true;
 }
 
 bool
-SmsParent::RecvGetSegmentInfoForText(const nsString& aText,
-                                     SmsSegmentInfoData* aResult)
-{
-  aResult->segments() = 0;
-  aResult->charsPerSegment() = 0;
-  aResult->charsAvailableInLastSegment() = 0;
-
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(smsService, true);
-
-  nsCOMPtr<nsIDOMMozSmsSegmentInfo> info;
-  nsresult rv = smsService->GetSegmentInfoForText(aText, getter_AddRefs(info));
-  NS_ENSURE_SUCCESS(rv, true);
-
-  int segments, charsPerSegment, charsAvailableInLastSegment;
-  if (NS_FAILED(info->GetSegments(&segments)) ||
-      NS_FAILED(info->GetCharsPerSegment(&charsPerSegment)) ||
-      NS_FAILED(info->GetCharsAvailableInLastSegment(&charsAvailableInLastSegment))) {
-    NS_ERROR("Can't get attribute values from nsIDOMMozSmsSegmentInfo");
-    return true;
-  }
-
-  aResult->segments() = segments;
-  aResult->charsPerSegment() = charsPerSegment;
-  aResult->charsAvailableInLastSegment() = charsAvailableInLastSegment;
-  return true;
-}
-
-bool
 SmsParent::RecvAddSilentNumber(const nsString& aNumber)
 {
   if (mSilentNumbers.Contains(aNumber)) {
     return true;
   }
 
   nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, true);
@@ -388,16 +359,18 @@ SmsParent::RecvPSmsRequestConstructor(PS
     case IPCSmsRequest::TRetrieveMessageRequest:
       return actor->DoRequest(aRequest.get_RetrieveMessageRequest());
     case IPCSmsRequest::TGetMessageRequest:
       return actor->DoRequest(aRequest.get_GetMessageRequest());
     case IPCSmsRequest::TDeleteMessageRequest:
       return actor->DoRequest(aRequest.get_DeleteMessageRequest());
     case IPCSmsRequest::TMarkMessageReadRequest:
       return actor->DoRequest(aRequest.get_MarkMessageReadRequest());
+    case IPCSmsRequest::TGetSegmentInfoForTextRequest:
+      return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest());
     default:
       MOZ_CRASH("Unknown type!");
   }
 
   return false;
 }
 
 PSmsRequestParent*
@@ -572,16 +545,34 @@ SmsRequestParent::DoRequest(const MarkMe
 
   if (NS_FAILED(rv)) {
     return NS_SUCCEEDED(NotifyMarkMessageReadFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
   }
 
   return true;
 }
 
+bool
+SmsRequestParent::DoRequest(const GetSegmentInfoForTextRequest& aRequest)
+{
+  nsresult rv = NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
+  if (smsService) {
+    rv = smsService->GetSegmentInfoForText(aRequest.text(), this);
+  }
+
+  if (NS_FAILED(rv)) {
+    return NS_SUCCEEDED(NotifyGetSegmentInfoForTextFailed(
+                          nsIMobileMessageCallback::INTERNAL_ERROR));
+  }
+
+  return true;
+}
+
 nsresult
 SmsRequestParent::SendReply(const MessageReply& aReply)
 {
   // The child process could die before this asynchronous notification, in which
   // case ActorDestroy() was called and mActorDestroyed is set to true. Return
   // an error here to avoid sending a message to the dead process.
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
@@ -669,16 +660,29 @@ SmsRequestParent::NotifyMessageMarkedRea
 }
 
 NS_IMETHODIMP
 SmsRequestParent::NotifyMarkMessageReadFailed(int32_t aError)
 {
   return SendReply(ReplyMarkeMessageReadFail(aError));
 }
 
+NS_IMETHODIMP
+SmsRequestParent::NotifySegmentInfoForTextGot(nsIDOMMozSmsSegmentInfo *aInfo)
+{
+  SmsSegmentInfo* info = static_cast<SmsSegmentInfo*>(aInfo);
+  return SendReply(ReplyGetSegmentInfoForText(info->GetData()));
+}
+
+NS_IMETHODIMP
+SmsRequestParent::NotifyGetSegmentInfoForTextFailed(int32_t aError)
+{
+  return SendReply(ReplyGetSegmentInfoForTextFail(aError));
+}
+
 /*******************************************************************************
  * MobileMessageCursorParent
  ******************************************************************************/
 
 NS_IMPL_ISUPPORTS1(MobileMessageCursorParent, nsIMobileMessageCursorCallback)
 
 void
 MobileMessageCursorParent::ActorDestroy(ActorDestroyReason aWhy)
--- a/dom/mobilemessage/src/ipc/SmsParent.h
+++ b/dom/mobilemessage/src/ipc/SmsParent.h
@@ -30,19 +30,16 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
 protected:
   virtual bool
   RecvHasSupport(bool* aHasSupport) MOZ_OVERRIDE;
 
   virtual bool
-  RecvGetSegmentInfoForText(const nsString& aText, SmsSegmentInfoData* aResult) MOZ_OVERRIDE;
-
-  virtual bool
   RecvAddSilentNumber(const nsString& aNumber) MOZ_OVERRIDE;
 
   virtual bool
   RecvRemoveSilentNumber(const nsString& aNumber) MOZ_OVERRIDE;
 
   SmsParent();
   virtual ~SmsParent()
   {
@@ -115,16 +112,19 @@ protected:
   DoRequest(const GetMessageRequest& aRequest);
 
   bool
   DoRequest(const DeleteMessageRequest& aRequest);
 
   bool
   DoRequest(const MarkMessageReadRequest& aRequest);
 
+  bool
+  DoRequest(const GetSegmentInfoForTextRequest& aRequest);
+
   nsresult
   SendReply(const MessageReply& aReply);
 };
 
 class MobileMessageCursorParent : public PMobileMessageCursorParent
                                 , public nsIMobileMessageCursorCallback
 {
   friend class SmsParent;
--- a/dom/mobilemessage/tests/marionette/test_getsegmentinfofortext.js
+++ b/dom/mobilemessage/tests/marionette/test_getsegmentinfofortext.js
@@ -44,33 +44,51 @@ let tasks = {
   run: function run() {
     this.next();
   }
 };
 
 function addTest(text, segments, charsPerSegment, charsAvailableInLastSegment) {
   tasks.push(function () {
     log("Testing '" + text + "' ...");
-    let info = manager.getSegmentInfoForText(text);
-    is(info.segments, segments, "info.segments");
-    is(info.charsPerSegment, charsPerSegment, "info.charsPerSegment");
-    is(info.charsAvailableInLastSegment, charsAvailableInLastSegment,
-       "info.charsAvailableInLastSegment");
+    let domRequest = manager.getSegmentInfoForText(text);
+    ok(domRequest, "DOMRequest object returned.");
+
+    domRequest.onsuccess = function(e) {
+      log("Received 'onsuccess' DOMRequest event.");
+
+      let result = e.target.result;
+      if (!result) {
+        ok(false, "getSegmentInfoForText() result is not valid.");
+        tasks.finish();
+        return;
+      }
 
-    tasks.next();
+      is(result.segments, segments, "info.segments");
+      is(result.charsPerSegment, charsPerSegment, "info.charsPerSegment");
+      is(result.charsAvailableInLastSegment, charsAvailableInLastSegment,
+         "info.charsAvailableInLastSegment");
+
+      tasks.next();
+    };
+
+    domRequest.onerror = function(e) {
+      ok(false, "Failed to call getSegmentInfoForText().");
+      tasks.finish();
+    };
   });
 }
 
 function addTestThrows(text) {
   tasks.push(function () {
     log("Testing '" + text + "' ...");
     try {
-      let info = manager.getSegmentInfoForText(text);
+      let domRequest = manager.getSegmentInfoForText(text);
 
-      ok(false, "Not thrown");
+      ok(false, "Not thrown.");
       tasks.finish();
     } catch (e) {
       tasks.next();
     }
   });
 }
 
 addTestThrows(null);
--- a/dom/mobilemessage/tests/marionette/test_segment_info.js
+++ b/dom/mobilemessage/tests/marionette/test_segment_info.js
@@ -7,123 +7,182 @@ const LEN_7BIT = 160;
 const LEN_7BIT_WITH_8BIT_REF = 153;
 const LEN_7BIT_WITH_16BIT_REF = 152;
 const LEN_UCS2 = 70;
 const LEN_UCS2_WITH_8BIT_REF = 67;
 const LEN_UCS2_WITH_16BIT_REF = 66;
 
 SpecialPowers.setBoolPref("dom.sms.enabled", true);
 let currentStrict7BitEncoding = false;
-SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding", currentStrict7BitEncoding);
+SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding",
+                          currentStrict7BitEncoding);
 SpecialPowers.addPermission("sms", true, document);
 
 let manager = window.navigator.mozMobileMessage;
 ok(manager instanceof MozMobileMessageManager,
    "manager is instance of " + manager.constructor);
 
 function times(str, n) {
   return (new Array(n + 1)).join(str);
 }
 
-function doTest(text, strict7BitEncoding, expected) {
-  if (strict7BitEncoding != currentStrict7BitEncoding) {
-    currentStrict7BitEncoding = strict7BitEncoding;
-    SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding", currentStrict7BitEncoding);
+let tasks = {
+  // List of test fuctions. Each of them should call |tasks.next()| when
+  // completed or |tasks.finish()| to jump to the last one.
+  _tasks: [],
+  _nextTaskIndex: 0,
+
+  push: function push(func) {
+    this._tasks.push(func);
+  },
+
+  next: function next() {
+    let index = this._nextTaskIndex++;
+    let task = this._tasks[index];
+    try {
+      task();
+    } catch (ex) {
+      ok(false, "test task[" + index + "] throws: " + ex);
+      // Run last task as clean up if possible.
+      if (index != this._tasks.length - 1) {
+        this.finish();
+      }
+    }
+  },
+
+  finish: function finish() {
+    this._tasks[this._tasks.length - 1]();
+  },
+
+  run: function run() {
+    this.next();
   }
+};
 
-  let result = manager.getSegmentInfoForText(text);
-  ok(result, "result of GetSegmentInfoForText is valid");
-  is(result.segments, expected[0], "segments");
-  is(result.charsPerSegment, expected[1], "charsPerSegment");
-  is(result.charsAvailableInLastSegment, expected[2], "charsAvailableInLastSegment");
-}
+function addTest(text, strict7BitEncoding, expected) {
+  tasks.push(function () {
+    if (strict7BitEncoding != currentStrict7BitEncoding) {
+      currentStrict7BitEncoding = strict7BitEncoding;
+      SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding",
+                                currentStrict7BitEncoding);
+    }
+
+    let domRequest = manager.getSegmentInfoForText(text);
+    ok(domRequest, "DOMRequest object returned.");
+
+    domRequest.onsuccess = function(e) {
+      log("Received 'onsuccess' DOMRequest event.");
 
-function cleanUp() {
-  SpecialPowers.removePermission("sms", document);
-  SpecialPowers.clearUserPref("dom.sms.enabled");
-  SpecialPowers.clearUserPref("dom.sms.strict7BitEncoding");
-  finish();
+      let result = e.target.result;
+      if (!result) {
+        ok(false, "getSegmentInfoForText() result is not valid.");
+        tasks.finish();
+        return;
+      }
+
+      is(result.segments, expected[0], "segments");
+      is(result.charsPerSegment, expected[1], "charsPerSegment");
+      is(result.charsAvailableInLastSegment, expected[2],
+         "charsAvailableInLastSegment");
+
+      tasks.next();
+    };
+
+    domRequest.onerror = function(e) {
+      ok(false, "Failed to call getSegmentInfoForText().");
+      tasks.finish();
+    };
+  });
 }
 
 // GSM 7Bit Alphabets:
 //
 // 'a' is in GSM default locking shift table, so it takes 1 septet.
-doTest("a", false, [1, LEN_7BIT, LEN_7BIT - 1]);
+addTest("a", false, [1, LEN_7BIT, LEN_7BIT - 1]);
 // '\u20ac' is in GSM default single shift table, so it takes 2 septets.
-doTest("\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 2]);
+addTest("\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 2]);
 // SP is defined in both locking shift and single shift tables.
-doTest(" ", false, [1, LEN_7BIT, LEN_7BIT - 1]);
+addTest(" ", false, [1, LEN_7BIT, LEN_7BIT - 1]);
 // Some combinations.
-doTest("a\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
-doTest("a ", false, [1, LEN_7BIT, LEN_7BIT - 2]);
-doTest("\u20aca", false, [1, LEN_7BIT, LEN_7BIT - 3]);
-doTest("\u20ac ", false, [1, LEN_7BIT, LEN_7BIT - 3]);
-doTest(" \u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
-doTest(" a", false, [1, LEN_7BIT, LEN_7BIT - 2]);
+addTest("a\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
+addTest("a ", false, [1, LEN_7BIT, LEN_7BIT - 2]);
+addTest("\u20aca", false, [1, LEN_7BIT, LEN_7BIT - 3]);
+addTest("\u20ac ", false, [1, LEN_7BIT, LEN_7BIT - 3]);
+addTest(" \u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
+addTest(" a", false, [1, LEN_7BIT, LEN_7BIT - 2]);
 
 // GSM 7Bit Alphabets (multipart):
 //
 // Exactly 160 locking shift table chararacters.
-doTest(times("a", LEN_7BIT), false, [1, LEN_7BIT, 0]);
+addTest(times("a", LEN_7BIT), false, [1, LEN_7BIT, 0]);
 // 161 locking shift table chararacters. We'll have |161 - 153 = 8| septets in
 // the 2nd segment.
-doTest(times("a", LEN_7BIT + 1), false,
-       [2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 8]);
+addTest(times("a", LEN_7BIT + 1), false,
+        [2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 8]);
 // |LEN_7BIT_WITH_8BIT_REF * 2| locking shift table chararacters.
-doTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2), false,
-       [2, LEN_7BIT_WITH_8BIT_REF, 0]);
+addTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2), false,
+        [2, LEN_7BIT_WITH_8BIT_REF, 0]);
 // |LEN_7BIT_WITH_8BIT_REF * 2 + 1| locking shift table chararacters.
-doTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2 + 1), false,
-       [3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 1]);
+addTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2 + 1), false,
+        [3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 1]);
 // Exactly 80 single shift table chararacters.
-doTest(times("\u20ac", LEN_7BIT / 2), false, [1, LEN_7BIT, 0]);
+addTest(times("\u20ac", LEN_7BIT / 2), false, [1, LEN_7BIT, 0]);
 // 81 single shift table chararacters. Because |Math.floor(153 / 2) = 76|, it
 // should left 5 septets in the 2nd segment.
-doTest(times("\u20ac", LEN_7BIT / 2 + 1), false,
-       [2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 10]);
+addTest(times("\u20ac", LEN_7BIT / 2 + 1), false,
+        [2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 10]);
 // |1 + 2 * 76| single shift table chararacters. We have only |153 - 76 * 2 = 1|
 // space left, but each single shift table character takes 2, so it will be
 // filled in the 3rd segment.
-doTest(times("\u20ac", 1 + 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
-       [3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 2]);
+addTest(times("\u20ac", 1 + 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
+        [3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 2]);
 // |2 * 76| single shift table chararacters + 1 locking shift table chararacter.
-doTest("a" + times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
-       [2, LEN_7BIT_WITH_8BIT_REF, 1]);
-doTest(times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)) + "a", false,
-       [2, LEN_7BIT_WITH_8BIT_REF, 0]);
+addTest("a" + times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
+        [2, LEN_7BIT_WITH_8BIT_REF, 1]);
+addTest(times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)) + "a", false,
+        [2, LEN_7BIT_WITH_8BIT_REF, 0]);
 
 // UCS2:
 //
 // '\u6afb' should be encoded as UCS2.
-doTest("\u6afb", false, [1, LEN_UCS2, LEN_UCS2 - 1]);
+addTest("\u6afb", false, [1, LEN_UCS2, LEN_UCS2 - 1]);
 // Combination of GSM 7bit alphabets.
-doTest("\u6afba", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
-doTest("\u6afb\u20ac", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
-doTest("\u6afb ", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
+addTest("\u6afba", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
+addTest("\u6afb\u20ac", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
+addTest("\u6afb ", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
 
 // UCS2 (multipart):
 //
 // Exactly 70 UCS2 chararacters.
-doTest(times("\u6afb", LEN_UCS2), false, [1, LEN_UCS2, 0]);
+addTest(times("\u6afb", LEN_UCS2), false, [1, LEN_UCS2, 0]);
 // 71 UCS2 chararacters. We'll have |71 - 67 = 4| chararacters in the 2nd
 // segment.
-doTest(times("\u6afb", LEN_UCS2 + 1), false,
-       [2, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 4]);
+addTest(times("\u6afb", LEN_UCS2 + 1), false,
+        [2, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 4]);
 // |LEN_UCS2_WITH_8BIT_REF * 2| ucs2 chararacters.
-doTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2), false,
-       [2, LEN_UCS2_WITH_8BIT_REF, 0]);
+addTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2), false,
+        [2, LEN_UCS2_WITH_8BIT_REF, 0]);
 // |LEN_7BIT_WITH_8BIT_REF * 2 + 1| ucs2 chararacters.
-doTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2 + 1), false,
-       [3, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 1]);
+addTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2 + 1), false,
+        [3, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 1]);
 
 // Strict 7-Bit Encoding:
 //
 // Should have no effect on GSM default alphabet characters.
-doTest("\u0041", true, [1, LEN_7BIT, LEN_7BIT - 1]);
+addTest("\u0041", true, [1, LEN_7BIT, LEN_7BIT - 1]);
 // "\u00c0"(À) should be mapped to "\u0041"(A).
-doTest("\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 1]);
+addTest("\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 1]);
 // Mixing mapped characters with unmapped ones.
-doTest("\u00c0\u0041", true, [1, LEN_7BIT, LEN_7BIT - 2]);
-doTest("\u0041\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 2]);
+addTest("\u00c0\u0041", true, [1, LEN_7BIT, LEN_7BIT - 2]);
+addTest("\u0041\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 2]);
 // UCS2 characters should be mapped to '*'.
-doTest("\u1234", true, [1, LEN_7BIT, LEN_7BIT - 1]);
+addTest("\u1234", true, [1, LEN_7BIT, LEN_7BIT - 1]);
+
 
-cleanUp();
+// WARNING: All tasks should be pushed before this!!!
+tasks.push(function cleanUp() {
+  SpecialPowers.removePermission("sms", document);
+  SpecialPowers.clearUserPref("dom.sms.enabled");
+  SpecialPowers.clearUserPref("dom.sms.strict7BitEncoding");
+  finish();
+});
+
+tasks.run();
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -2989,17 +2989,17 @@ RadioInterface.prototype = {
     }
 
     // Re-sync options.segmentMaxSeq with actual length of returning array.
     options.segmentMaxSeq = options.segments.length;
 
     return options;
   },
 
-  getSegmentInfoForText: function getSegmentInfoForText(text) {
+  getSegmentInfoForText: function getSegmentInfoForText(text, request) {
     let strict7BitEncoding;
     try {
       strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
     } catch (e) {
       strict7BitEncoding = false;
     }
 
     let options = this._fragmentText(text, null, strict7BitEncoding);
@@ -3010,20 +3010,21 @@ RadioInterface.prototype = {
       if (options.dcs == RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET) {
         // In UCS2 encoding, encodedBodyLength is in octets.
         charsInLastSegment /= 2;
       }
     } else {
       charsInLastSegment = 0;
     }
 
-    let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq,
-                                                            options.segmentChars,
-                                                            options.segmentChars - charsInLastSegment);
-    return result;
+    let result = gMobileMessageService
+                 .createSmsSegmentInfo(options.segmentMaxSeq,
+                                       options.segmentChars,
+                                       options.segmentChars - charsInLastSegment);
+    request.notifySegmentInfoForTextGot(result);
   },
 
   sendSMS: function sendSMS(number, message, silent, request) {
     let strict7BitEncoding;
     try {
       strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
     } catch (e) {
       strict7BitEncoding = false;
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -1,17 +1,16 @@
 /* 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 "nsISupports.idl"
 
 interface nsIDOMMozIccInfo;
 interface nsIDOMMozMobileConnectionInfo;
-interface nsIDOMMozSmsSegmentInfo;
 interface nsIMobileMessageCallback;
 
 [scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
 interface nsIRILDataCallInfo : nsISupports
 {
   /**
    * Current data call state, one of the
    * nsINetworkInterface::NETWORK_STATE_* constants.
@@ -74,17 +73,17 @@ interface nsIRilContext : nsISupports
 
   readonly attribute nsIDOMMozIccInfo iccInfo;
 
   readonly attribute nsIDOMMozMobileConnectionInfo voice;
 
   readonly attribute nsIDOMMozMobileConnectionInfo data;
 };
 
-[scriptable, uuid(5efcd358-080e-46d6-a7f7-4f36c204eec3)]
+[scriptable, uuid(a50d65aa-00da-11e3-b954-7bfb233d98fc)]
 interface nsIRadioInterface : nsISupports
 {
   readonly attribute nsIRilContext rilContext;
 
   /**
    * PDP APIs
    */
   void setupDataCallByType(in DOMString apntype);
@@ -94,17 +93,18 @@ interface nsIRadioInterface : nsISupport
   void registerDataCallCallback(in nsIRILDataCallback callback);
   void unregisterDataCallCallback(in nsIRILDataCallback callback);
 
   void updateRILNetworkInterface();
 
   /**
    * SMS-related functionality.
    */
-  nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
+  void getSegmentInfoForText(in DOMString text,
+                             in nsIMobileMessageCallback request);
 
   void sendSMS(in DOMString number,
                in DOMString message,
                in boolean silent,
                in nsIMobileMessageCallback request);
 };
 
 [scriptable, uuid(44b03951-1444-4c03-bd37-0bcb3a01b56f)]
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -1653,26 +1653,28 @@ AndroidBridge::SetURITitle(const nsAStri
     AutoLocalJNIFrame jniFrame(env);
     jstring jstrURI = NewJavaString(&jniFrame, aURI);
     jstring jstrTitle = NewJavaString(&jniFrame, aTitle);
     env->CallStaticVoidMethod(mGeckoAppShellClass, jSetUriTitle, jstrURI, jstrTitle);
 }
 
 nsresult
 AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
-                                     dom::mobilemessage::SmsSegmentInfoData* aData)
+                                     nsIMobileMessageCallback* aRequest)
 {
 #ifndef MOZ_WEBSMS_BACKEND
     return NS_ERROR_FAILURE;
 #else
     ALOG_BRIDGE("AndroidBridge::GetSegmentInfoForText");
 
-    aData->segments() = 0;
-    aData->charsPerSegment() = 0;
-    aData->charsAvailableInLastSegment() = 0;
+    dom::mobilemessage::SmsSegmentInfoData data;
+
+    data.segments() = 0;
+    data.charsPerSegment() = 0;
+    data.charsAvailableInLastSegment() = 0;
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return NS_ERROR_FAILURE;
 
     AutoLocalJNIFrame jniFrame(env);
     jstring jText = NewJavaString(&jniFrame, aText);
     jobject obj = env->CallStaticObjectMethod(mAndroidSmsMessageClass,
@@ -1681,23 +1683,27 @@ AndroidBridge::GetSegmentInfoForText(con
         return NS_ERROR_FAILURE;
 
     jintArray arr = static_cast<jintArray>(obj);
     if (!arr || env->GetArrayLength(arr) != 4)
         return NS_ERROR_FAILURE;
 
     jint* info = env->GetIntArrayElements(arr, JNI_FALSE);
 
-    aData->segments() = info[0]; // msgCount
-    aData->charsPerSegment() = info[2]; // codeUnitsRemaining
+    data.segments() = info[0]; // msgCount
+    data.charsPerSegment() = info[2]; // codeUnitsRemaining
     // segmentChars = (codeUnitCount + codeUnitsRemaining) / msgCount
-    aData->charsAvailableInLastSegment() = (info[1] + info[2]) / info[0];
+    data.charsAvailableInLastSegment() = (info[1] + info[2]) / info[0];
 
     env->ReleaseIntArrayElements(arr, info, JNI_ABORT);
-    return NS_OK;
+
+    // TODO Bug 908598 - Should properly use |QueueSmsRequest(...)| to queue up
+    // the nsIMobileMessageCallback just like other functions.
+    nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
+    return aRequest->NotifySegmentInfoForTextGot(info);
 #endif
 }
 
 void
 AndroidBridge::SendMessage(const nsAString& aNumber,
                            const nsAString& aMessage,
                            nsIMobileMessageCallback* aRequest)
 {
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -351,17 +351,17 @@ public:
 
     void CloseCamera();
 
     void EnableBatteryNotifications();
     void DisableBatteryNotifications();
     void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
 
     nsresult GetSegmentInfoForText(const nsAString& aText,
-                                   dom::mobilemessage::SmsSegmentInfoData* aData);
+                                   nsIMobileMessageCallback* aRequest);
     void SendMessage(const nsAString& aNumber, const nsAString& aText,
                      nsIMobileMessageCallback* aRequest);
     void GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest);
     void DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest);
     void CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter,
                            bool aReverse, nsIMobileMessageCallback* aRequest);
     void GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest);
     void ClearMessageList(int32_t aListId);