Bug 674725 - Part AQ - Read the next message in the list (Android backend). r=cjones
authorMounir Lamouri <mounir.lamouri@gmail.com>
Thu, 22 Dec 2011 23:16:59 +0100
changeset 84734 cd7e8a34d4f39c89741250d6d576d02872d5eba9
parent 84733 afca8fef2e4e15e6ccc7703326e8d093735dc425
child 84735 b045d642ed32cb932e9352c262496643ec917762
push id443
push usertim.taubert@gmx.de
push dateWed, 18 Jan 2012 12:23:22 +0000
treeherderfx-team@f93675b9e0ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs674725
milestone12.0a1
Bug 674725 - Part AQ - Read the next message in the list (Android backend). r=cjones
dom/sms/src/SmsRequestManager.cpp
dom/sms/src/SmsRequestManager.h
dom/sms/src/android/SmsDatabaseService.cpp
dom/sms/src/ipc/PSms.ipdl
dom/sms/src/ipc/SmsChild.cpp
dom/sms/src/ipc/SmsChild.h
embedding/android/GeckoAppShell.java
embedding/android/GeckoSmsManager.java
mozglue/android/APKOpen.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
--- a/dom/sms/src/SmsRequestManager.cpp
+++ b/dom/sms/src/SmsRequestManager.cpp
@@ -225,11 +225,18 @@ SmsRequestManager::NotifyCreateMessageLi
   SmsRequest* request = GetRequest(aRequestId);
 
   nsCOMPtr<SmsCursor> cursor = new SmsCursor(aListId, nsnull, request);
   cursor->SetMessage(aMessage);
 
   NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
 }
 
+void
+SmsRequestManager::NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
+{
+  // TODO: implement
+  printf_stderr("\nHERE\n\n");
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/SmsRequestManager.h
+++ b/dom/sms/src/SmsRequestManager.h
@@ -67,16 +67,17 @@ public:
   void NotifySmsSent(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
   void NotifySmsSendFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
   void NotifyGotSms(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
   void NotifyGetSmsFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
   void NotifySmsDeleted(PRInt32 aRequestId, bool aDeleted);
   void NotifySmsDeleteFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
   void NotifyNoMessageInList(PRInt32 aRequestId);
   void NotifyCreateMessageList(PRInt32 aRequestId, PRInt32 aListId, nsIDOMMozSmsMessage* aMessage);
+  void NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
 
 private:
   static SmsRequestManager* sInstance;
 
   nsresult DispatchTrustedEventToRequest(const nsAString& aEventName,
                                          nsIDOMMozSmsRequest* aRequest);
   SmsRequest* GetRequest(PRInt32 aRequestId);
 
--- a/dom/sms/src/android/SmsDatabaseService.cpp
+++ b/dom/sms/src/android/SmsDatabaseService.cpp
@@ -98,15 +98,19 @@ SmsDatabaseService::CreateMessageList(ns
   );
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsDatabaseService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
                                          PRUint64 aProcessId)
 {
-  // TODO: implement
+  if (!AndroidBridge::Bridge()) {
+    return NS_OK;
+  }
+
+  AndroidBridge::Bridge()->GetNextMessageInList(aListId, aRequestId, aProcessId);
   return NS_OK;
 }
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ipc/PSms.ipdl
+++ b/dom/sms/src/ipc/PSms.ipdl
@@ -89,16 +89,18 @@ child:
 
     NotifyRequestSmsDeleteFailed(PRInt32 aError, PRInt32 aRequestId,
                                  PRUint64 aProcessId);
 
     NotifyRequestNoMessageInList(PRInt32 aRequestId, PRUint64 aProcessId);
 
     NotifyRequestCreateMessageList(PRInt32 aListId, SmsMessageData aMessageData, PRInt32 aRequestId, PRUint64 aProcessId);
 
+    NotifyRequestGotNextMessage(SmsMessageData aMessageData, PRInt32 aRequestId, PRUint64 aProcessId);
+
 parent:
     sync HasSupport()
         returns (bool aHasSupport);
 
     sync GetNumberOfMessagesForText(nsString aText)
         returns (PRUint16 aNumber);
 
     SendMessage(nsString aNumber, nsString aMessage, PRInt32 aRequestId,
--- a/dom/sms/src/ipc/SmsChild.cpp
+++ b/dom/sms/src/ipc/SmsChild.cpp
@@ -201,11 +201,25 @@ SmsChild::RecvNotifyRequestCreateMessage
     return true;
   }
 
   nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
   SmsRequestManager::GetInstance()->NotifyCreateMessageList(aRequestId, aListId, message);
   return true;
 }
 
+bool
+SmsChild::RecvNotifyRequestGotNextMessage(const SmsMessageData& aMessageData,
+                                          const PRInt32& aRequestId,
+                                          const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
+  SmsRequestManager::GetInstance()->NotifyGotNextMessage(aRequestId, message);
+  return true;
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ipc/SmsChild.h
+++ b/dom/sms/src/ipc/SmsChild.h
@@ -53,15 +53,16 @@ public:
   NS_OVERRIDE virtual bool RecvNotifyRequestSmsSent(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
   NS_OVERRIDE virtual bool RecvNotifyRequestSmsSendFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
   NS_OVERRIDE virtual bool RecvNotifyRequestGotSms(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
   NS_OVERRIDE virtual bool RecvNotifyRequestGetSmsFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
   NS_OVERRIDE virtual bool RecvNotifyRequestSmsDeleted(const bool& aDeleted, const PRInt32& aRequestId, const PRUint64& aProcessId);
   NS_OVERRIDE virtual bool RecvNotifyRequestSmsDeleteFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
   NS_OVERRIDE virtual bool RecvNotifyRequestNoMessageInList(const PRInt32& aRequestId, const PRUint64& aProcessId);
   NS_OVERRIDE virtual bool RecvNotifyRequestCreateMessageList(const PRInt32& aListId, const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestGotNextMessage(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_sms_SmsChild_h
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -127,16 +127,17 @@ public class GeckoAppShell
     public static native void notifySmsDelivered(int aId, String aReceiver, String aBody, long aTimestamp);
     public static native void notifySmsSendFailed(int aError, int aRequestId, long aProcessId);
     public static native void notifyGetSms(int aId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyGetSmsFailed(int aError, int aRequestId, long aProcessId);
     public static native void notifySmsDeleted(boolean aDeleted, int aRequestId, long aProcessId);
     public static native void notifySmsDeleteFailed(int aError, int aRequestId, long aProcessId);
     public static native void notifyNoMessageInList(int aRequestId, long aProcessId);
     public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+    public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
 
     // A looper thread, accessed by GeckoAppShell.getHandler
     private static class LooperThread extends Thread {
         public SynchronousQueue<Handler> mHandlerQueue =
             new SynchronousQueue<Handler>();
         
         public void run() {
             Looper.prepare();
@@ -1717,16 +1718,20 @@ public class GeckoAppShell
     public static void deleteMessage(int aMessageId, int aRequestId, long aProcessId) {
         GeckoSmsManager.deleteMessage(aMessageId, aRequestId, aProcessId);
     }
 
     public static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId) {
         GeckoSmsManager.createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, aProcessId);
     }
 
+    public static void getNextMessageInList(int aListId, int aRequestId, long aProcessId) {
+        GeckoSmsManager.getNextMessageInList(aListId, aRequestId, aProcessId);
+    }
+
     public static boolean isTablet() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
             Configuration config = GeckoApp.mAppContext.getResources().getConfiguration();
             // xlarge is defined by android as screens larger than 960dp x 720dp
             // and should include most devices ~7in and up.
             // http://developer.android.com/guide/practices/screens_support.html
             if ((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE) {
                 return true;
--- a/embedding/android/GeckoSmsManager.java
+++ b/embedding/android/GeckoSmsManager.java
@@ -848,13 +848,72 @@ public class GeckoSmsManager
     }
 
     if (!SmsIOThread.getInstance().execute(new CreateMessageListRunnable(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, aProcessId))) {
       Log.e("GeckoSmsManager", "Failed to add CreateMessageListRunnable to the SmsIOThread");
       // TODO: send an error notification
     }
   }
 
+  public static void getNextMessageInList(int aListId, int aRequestId, long aProcessId) {
+    class GetNextMessageInListRunnable implements Runnable {
+      private int mListId;
+      private int mRequestId;
+      private long mProcessId;
+
+      GetNextMessageInListRunnable(int aListId, int aRequestId, long aProcessId) {
+        mListId = aListId;
+        mRequestId = aRequestId;
+        mProcessId = aProcessId;
+      }
+
+      @Override
+      public void run() {
+        class UnexpectedDeliveryStateException extends Exception { };
+
+        try {
+          Cursor cursor = MessagesListManager.getInstance().get(mListId);
+
+          if (!cursor.moveToNext()) {
+            MessagesListManager.getInstance().remove(mListId);
+            GeckoAppShell.notifyNoMessageInList(mRequestId, mProcessId);
+            return;
+          }
+
+          int type = cursor.getInt(cursor.getColumnIndex("type"));
+          String sender = "";
+          String receiver = "";
+
+          if (type == kSmsTypeInbox) {
+            sender = cursor.getString(cursor.getColumnIndex("address"));
+          } else if (type == kSmsTypeSentbox) {
+            receiver = cursor.getString(cursor.getColumnIndex("address"));
+          } else {
+            throw new UnexpectedDeliveryStateException();
+          }
+
+          int listId = MessagesListManager.getInstance().add(cursor);
+          GeckoAppShell.notifyGotNextMessage(cursor.getInt(cursor.getColumnIndex("_id")),
+                                             receiver, sender,
+                                             cursor.getString(cursor.getColumnIndex("body")),
+                                             cursor.getLong(cursor.getColumnIndex("date")),
+                                             mRequestId, mProcessId);
+        } catch (UnexpectedDeliveryStateException e) {
+          Log.e("GeckoSmsManager", "Unexcepted delivery state type: " + e);
+          // TODO: send an error notification
+        } catch (Exception e) {
+          Log.e("GeckoSmsManager", "Error while trying to get the next message of a list: " + e);
+          // TODO: send an error notification
+        }
+      }
+    }
+
+    if (!SmsIOThread.getInstance().execute(new GetNextMessageInListRunnable(aListId, aRequestId, aProcessId))) {
+      Log.e("GeckoSmsManager", "Failed to add GetNextMessageInListRunnable to the SmsIOThread");
+      // TODO: send an error notification
+    }
+  }
+
   public static void shutdown() {
     SmsIOThread.getInstance().interrupt();
     MessagesListManager.getInstance().clear();
   }
 }
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -293,16 +293,17 @@ SHELL_WRAPPER6(notifySmsSent, jint, jstr
 SHELL_WRAPPER4(notifySmsDelivered, jint, jstring, jstring, jlong);
 SHELL_WRAPPER3(notifySmsSendFailed, jint, jint, jlong);
 SHELL_WRAPPER7(notifyGetSms, jint, jstring, jstring, jstring, jlong, jint, jlong);
 SHELL_WRAPPER3(notifyGetSmsFailed, jint, jint, jlong);
 SHELL_WRAPPER3(notifySmsDeleted, jboolean, jint, jlong);
 SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong);
 SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong);
 SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong);
+SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong);
 
 static void * xul_handle = NULL;
 static time_t apk_mtime = 0;
 #ifdef DEBUG
 extern "C" int extractLibs = 1;
 #else
 extern "C" int extractLibs = 0;
 #endif
@@ -690,16 +691,17 @@ loadLibs(const char *apkName)
   GETFUNC(notifySmsDelivered);
   GETFUNC(notifySmsSendFailed);
   GETFUNC(notifyGetSms);
   GETFUNC(notifyGetSmsFailed);
   GETFUNC(notifySmsDeleted);
   GETFUNC(notifySmsDeleteFailed);
   GETFUNC(notifyNoMessageInList);
   GETFUNC(notifyListCreated);
+  GETFUNC(notifyGotNextMessage);
 #undef GETFUNC
   sStartupTimeline = (uint64_t *)__wrap_dlsym(xul_handle, "_ZN7mozilla15StartupTimeline16sStartupTimelineE");
   gettimeofday(&t1, 0);
   struct rusage usage2;
   getrusage(RUSAGE_THREAD, &usage2);
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %dms total, %dms user, %dms system, %d faults",
                       (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000, 
                       (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000,
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -168,16 +168,17 @@ AndroidBridge::Init(JNIEnv *jEnv,
     jMarkUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V");
 
     jNumberOfMessages = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNumberOfMessagesForText", "(Ljava/lang/String;)I");
     jSendMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "sendMessage", "(Ljava/lang/String;Ljava/lang/String;IJ)V");
     jSaveSentMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "saveSentMessage", "(Ljava/lang/String;Ljava/lang/String;J)I");
     jGetMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMessage", "(IIJ)V");
     jDeleteMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "deleteMessage", "(IIJ)V");
     jCreateMessageList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;IIZIJ)V");
+    jGetNextMessageinList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNextMessageInList", "(IIJ)V");
 
     jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
     jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
     jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
     jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
     jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
     jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
 
@@ -1406,16 +1407,24 @@ AndroidBridge::CreateMessageList(const d
 
     JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jCreateMessageList,
                                 aFilter.startDate(), aFilter.endDate(),
                                 numbers, aFilter.numbers().Length(),
                                 aFilter.delivery(), aReverse, aRequestId,
                                 aProcessId);
 }
 
+void
+AndroidBridge::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId, PRUint64 aProcessId)
+{
+    ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
+
+    JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jGetNextMessageinList, aListId, aRequestId, aProcessId);
+}
+
 void *
 AndroidBridge::LockBitmap(jobject bitmap)
 {
     int err;
     void *buf;
 
     if ((err = AndroidBitmap_lockPixels(JNI(), bitmap, &buf)) != 0) {
         ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err);
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -341,16 +341,17 @@ public:
     void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
 
     PRUint16 GetNumberOfMessagesForText(const nsAString& aText);
     void SendMessage(const nsAString& aNumber, const nsAString& aText, PRInt32 aRequestId, PRUint64 aProcessId);
     PRInt32 SaveSentMessage(const nsAString& aRecipient, const nsAString& aBody, PRUint64 aDate);
     void GetMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
     void DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
     void CreateMessageList(const dom::sms::SmsFilterData& aFilter, bool aReverse, PRInt32 aRequestId, PRUint64 aProcessId);
+    void GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId, PRUint64 aProcessId);
 
     bool IsTablet();
 
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
@@ -435,16 +436,17 @@ protected:
     jmethodID jEmitGeckoAccessibilityEvent;
 
     jmethodID jNumberOfMessages;
     jmethodID jSendMessage;
     jmethodID jSaveSentMessage;
     jmethodID jGetMessage;
     jmethodID jDeleteMessage;
     jmethodID jCreateMessageList;
+    jmethodID jGetNextMessageinList;
 
     // stuff we need for CallEglCreateWindowSurface
     jclass jEGLSurfaceImplClass;
     jclass jEGLContextImplClass;
     jclass jEGLConfigImplClass;
     jclass jEGLDisplayImplClass;
     jclass jEGLContextClass;
     jclass jEGL10Class;
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -96,16 +96,17 @@ extern "C" {
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsDelivered(JNIEnv* jenv, jclass, jint, jstring, jstring, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsSendFailed(JNIEnv* jenv, jclass, jint, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGetSms(JNIEnv* jenv, jclass, jint, jstring, jstring, jstring, jlong, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGetSmsFailed(JNIEnv* jenv, jclass, jint, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsDeleted(JNIEnv* jenv, jclass, jboolean, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsDeleteFailed(JNIEnv* jenv, jclass, jint, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyNoMessageInList(JNIEnv* jenv, jclass, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyListCreated(JNIEnv* jenv, jclass, jint, jint, jstring, jstring, jstring, jlong, jint, jlong);
+    NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGotNextMessage(JNIEnv* jenv, jclass, jint, jstring, jstring, jstring, jlong, jint, jlong);
 
 #ifdef MOZ_JAVA_COMPOSITOR
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass);
     NS_EXPORT bool JNICALL Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass);
 #endif
 }
 
 
@@ -735,16 +736,73 @@ Java_org_mozilla_gecko_GeckoAppShell_not
     SmsMessageData message(aMessageId, state, nsJNIString(aSender, jenv),
                            receiver, nsJNIString(aBody, jenv), aTimestamp);
 
     nsCOMPtr<nsIRunnable> runnable =
       new NotifyCreateMessageListRunnable(aListId, message, aRequestId, aProcessId);
     NS_DispatchToMainThread(runnable);
 }
 
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_notifyGotNextMessage(JNIEnv* jenv, jclass,
+                                                          jint aMessageId,
+                                                          jstring aReceiver,
+                                                          jstring aSender,
+                                                          jstring aBody,
+                                                          jlong aTimestamp,
+                                                          jint aRequestId,
+                                                          jlong aProcessId)
+{
+    class NotifyGotNextMessageRunnable : public nsRunnable {
+    public:
+      NotifyGotNextMessageRunnable(const SmsMessageData& aMessage,
+                                   PRInt32 aRequestId, PRUint64 aProcessId)
+        : mMessage(aMessage)
+        , mRequestId(aRequestId)
+        , mProcessId(aProcessId)
+      {}
+
+      NS_IMETHODIMP Run() {
+        if (mProcessId == 0) { // Parent process.
+          nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessage);
+          SmsRequestManager::GetInstance()->NotifyGotNextMessage(mRequestId,
+                                                                 message);
+        } else { // Content process.
+          nsTArray<SmsParent*> spList;
+          SmsParent::GetAll(spList);
+
+          for (PRUint32 i=0; i<spList.Length(); ++i) {
+            unused << spList[i]->SendNotifyRequestGotNextMessage(mMessage,
+                                                                 mRequestId,
+                                                                 mProcessId);
+          }
+        }
+
+        return NS_OK;
+      }
+
+    private:
+      SmsMessageData mMessage;
+      PRInt32        mRequestId;
+      PRUint64       mProcessId;
+    };
+
+
+    nsJNIString receiver = nsJNIString(aReceiver, jenv);
+    DeliveryState state = receiver.IsEmpty() ? eDeliveryState_Received
+                                             : eDeliveryState_Sent;
+
+    SmsMessageData message(aMessageId, state, nsJNIString(aSender, jenv),
+                           receiver, nsJNIString(aBody, jenv), aTimestamp);
+
+    nsCOMPtr<nsIRunnable> runnable =
+      new NotifyGotNextMessageRunnable(message, aRequestId, aProcessId);
+    NS_DispatchToMainThread(runnable);
+}
+
 #ifdef MOZ_JAVA_COMPOSITOR
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass)
 {
     nsWindow::BindToTexture();
 }