Bug 674725 - Part AL - Store Android Cursors to keep track of created message lists. r=cjones
authorMounir Lamouri <mounir.lamouri@gmail.com>
Thu, 22 Dec 2011 23:16:22 +0100
changeset 84723 547e3a3d109ee4d1a250b0f08f5fe5220283612c
parent 84722 0da63ad71e41b11e0fd4c98ce52afa5f2db0429c
child 84724 3b95e40950156f9fa9298272bd5d65225975dd43
push id21873
push usermlamouri@mozilla.com
push dateWed, 18 Jan 2012 10:29:07 +0000
treeherdermozilla-central@7538f4d4697c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs674725
milestone12.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 674725 - Part AL - Store Android Cursors to keep track of created message lists. r=cjones
embedding/android/GeckoAppShell.java
embedding/android/GeckoSmsManager.java
mozglue/android/APKOpen.cpp
widget/android/AndroidJNI.cpp
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -125,16 +125,18 @@ public class GeckoAppShell
     public static native int  saveMessageInSentbox(String aReceiver, String aBody, long aTimestamp);
     public static native void notifySmsSent(int aId, String aReceiver, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     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);
 
     // 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();
--- a/embedding/android/GeckoSmsManager.java
+++ b/embedding/android/GeckoSmsManager.java
@@ -247,16 +247,81 @@ class SmsIOThread extends Thread {
     Looper.prepare();
 
     mHandler = new Handler();
 
     Looper.loop();
   }
 }
 
+class MessagesListManager
+{
+  private static final MessagesListManager sInstance = new MessagesListManager();
+
+  public static MessagesListManager getInstance() {
+    return sInstance;
+  }
+
+  private ArrayList<Cursor> mCursors = new ArrayList<Cursor>(0);
+
+  public int add(Cursor aCursor) {
+    int size = mCursors.size();
+
+    for (int i=0; i<size; ++i) {
+      if (mCursors.get(i) == null) {
+        mCursors.set(i, aCursor);
+        return i;
+      }
+    }
+
+    mCursors.add(aCursor);
+    return size;
+  }
+
+  public Cursor get(int aId) {
+    if (aId < 0 || mCursors.size() <= aId) {
+      Log.e("GeckoSmsManager", "Trying to get an unknown list!");
+      return null;
+    }
+
+    Cursor cursor = mCursors.get(aId);
+    if (cursor == null) {
+      Log.e("GeckoSmsManager", "Trying to get an empty list!");
+    }
+
+    return cursor;
+  }
+
+  public void remove(int aId) {
+    if (aId < 0 || mCursors.size() <= aId) {
+      Log.e("GeckoSmsManager", "Trying to destroy an unknown list!");
+      return;
+    }
+
+    Cursor cursor = mCursors.set(aId, null);
+    if (cursor == null) {
+      Log.e("GeckoSmsManager", "Trying to destroy an empty list!");
+      return;
+    }
+
+    cursor.close();
+  }
+
+  public void clear() {
+    for (int i=0; i<mCursors.size(); ++i) {
+      Cursor c = mCursors.get(i);
+      if (c != null) {
+        c.close();
+      }
+    }
+
+    mCursors.clear();
+  }
+}
+
 public class GeckoSmsManager
   extends BroadcastReceiver
 {
   public final static String ACTION_SMS_RECEIVED  = "android.provider.Telephony.SMS_RECEIVED";
   public final static String ACTION_SMS_SENT      = "org.mozilla.gecko.SMS_SENT";
   public final static String ACTION_SMS_DELIVERED = "org.mozilla.gecko.SMS_DELIVERED";
 
   /*
@@ -685,18 +750,20 @@ public class GeckoSmsManager
         mReverse = aReverse;
         mRequestId = aRequestId;
         mProcessId = aProcessId;
       }
 
       @Override
       public void run() {
         class UnexpectedDeliveryStateException extends Exception { };
+        class InvalidTypeException extends Exception { }
 
-        Cursor c = null;
+        Cursor cursor = null;
+        boolean closeCursor = true;
 
         try {
           // TODO: should use the |selectionArgs| argument in |ContentResolver.query()|.
           ArrayList<String> restrictions = new ArrayList<String>();
 
           if (mStartDate != 0) {
             restrictions.add("date >= " + mStartDate);
           }
@@ -711,56 +778,83 @@ public class GeckoSmsManager
             for (int i=1; i<mNumbersCount; ++i) {
               numberRestriction += ", '" + mNumbers[i] + "'";
             }
             numberRestriction += ")";
 
             restrictions.add(numberRestriction);
           }
 
-          if (mDeliveryState != kDeliveryStateUnknown) {
-            if (mDeliveryState == kDeliveryStateSent) {
-              restrictions.add("type = " + kSmsTypeSentbox);
-            } else if (mDeliveryState == kDeliveryStateReceived) {
-              restrictions.add("type = " + kSmsTypeInbox);
-            } else {
-              throw new UnexpectedDeliveryStateException();
-            }
+          if (mDeliveryState == kDeliveryStateUnknown) {
+            restrictions.add("type IN ('" + kSmsTypeSentbox + "', '" + kSmsTypeInbox + "')");
+          } else if (mDeliveryState == kDeliveryStateSent) {
+            restrictions.add("type = " + kSmsTypeSentbox);
+          } else if (mDeliveryState == kDeliveryStateReceived) {
+            restrictions.add("type = " + kSmsTypeInbox);
+          } else {
+            throw new UnexpectedDeliveryStateException();
           }
 
           String restrictionText = restrictions.size() > 0 ? restrictions.get(0) : "";
 
           for (int i=1; i<restrictions.size(); ++i) {
             restrictionText += " AND " + restrictions.get(i);
           }
 
           ContentResolver cr = GeckoApp.surfaceView.getContext().getContentResolver();
-          c = cr.query(kSmsContentUri, kRequiredMessageRows, restrictionText, null,
-                       mReverse ? "date DESC" : "date ASC");
+          cursor = cr.query(kSmsContentUri, kRequiredMessageRows, restrictionText, null,
+                            mReverse ? "date DESC" : "date ASC");
+
+          if (cursor.getCount() == 0) {
+            GeckoAppShell.notifyNoMessageInList(mRequestId, mProcessId);
+            return;
+          }
+
+          cursor.moveToFirst();
+
+          int type = cursor.getInt(cursor.getColumnIndex("type"));
+          String sender = "";
+          String receiver = "";
 
-          // TODO: store the cursor
-          // TODO: create a list id
-          // TODO: send a notification
+          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);
+          closeCursor = false;
+          GeckoAppShell.notifyListCreated(listId,
+                                          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 create a message list cursor: " + e);
           // TODO: send an error notification
         } finally {
-          // TODO: remove when close will be callable from the DOM side.
-          if (c != null) {
-            c.close();
+          // Close the cursor if MessagesListManager isn't taking care of it.
+          // We could also just check if it is in the MessagesListManager list but
+          // that would be less efficient.
+          if (cursor != null && closeCursor) {
+            cursor.close();
           }
         }
       }
     }
 
     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 shutdown() {
     SmsIOThread.getInstance().interrupt();
+    MessagesListManager.getInstance().clear();
   }
 }
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -247,16 +247,34 @@ Java_org_mozilla_gecko_GeckoAppShell_ ##
 typedef return_type (*name ## _t)(JNIEnv *, jclass, type1 one, type2 two, type3 three, type4 four, type5 five, type6 six, type7 seven); \
 static name ## _t f_ ## name; \
 extern "C" NS_EXPORT return_type JNICALL \
 Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc, type1 one, type2 two, type3 three, type4 four, type5 five, type6 six, type7 seven) \
 { \
   return f_ ## name(jenv, jc, one, two, three, four, five, six, seven); \
 }
 
+#define SHELL_WRAPPER8(name,type1,type2,type3,type4,type5,type6,type7,type8) \
+typedef void (*name ## _t)(JNIEnv *, jclass, type1 one, type2 two, type3 three, type4 four, type5 five, type6 six, type7 seven, type8 eight); \
+static name ## _t f_ ## name; \
+extern "C" NS_EXPORT void JNICALL \
+Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc, type1 one, type2 two, type3 three, type4 four, type5 five, type6 six, type7 seven, type8 eight) \
+{ \
+  f_ ## name(jenv, jc, one, two, three, four, five, six, seven, eight); \
+}
+
+#define SHELL_WRAPPER8_WITH_RETURN(name, return_type, type1, type2, type3, type4, type5, type6, type7, type8) \
+typedef return_type (*name ## _t)(JNIEnv *, jclass, type1 one, type2 two, type3 three, type4 four, type5 five, type6 six, type7 seven, type8 eight); \
+static name ## _t f_ ## name; \
+extern "C" NS_EXPORT return_type JNICALL \
+Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc, type1 one, type2 two, type3 three, type4 four, type5 five, type6 six, type7 seven, type8 eight) \
+{ \
+  return f_ ## name(jenv, jc, one, two, three, four, five, six, seven, eight); \
+}
+
 SHELL_WRAPPER0(nativeInit)
 SHELL_WRAPPER1(nativeRun, jstring)
 SHELL_WRAPPER1(notifyGeckoOfEvent, jobject)
 SHELL_WRAPPER0(processNextNativeEvent)
 SHELL_WRAPPER1(setSurfaceView, jobject)
 SHELL_WRAPPER1(setSoftwareLayerClient, jobject)
 SHELL_WRAPPER0(onResume)
 SHELL_WRAPPER0(onLowMemory)
@@ -273,16 +291,18 @@ SHELL_WRAPPER0_WITH_RETURN(testDirectTex
 SHELL_WRAPPER3_WITH_RETURN(saveMessageInSentbox, jint, jstring, jstring, jlong);
 SHELL_WRAPPER6(notifySmsSent, jint, jstring, jstring, jlong, jint, jlong);
 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);
 
 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
@@ -668,16 +688,18 @@ loadLibs(const char *apkName)
   GETFUNC(saveMessageInSentbox);
   GETFUNC(notifySmsSent);
   GETFUNC(notifySmsDelivered);
   GETFUNC(notifySmsSendFailed);
   GETFUNC(notifyGetSms);
   GETFUNC(notifyGetSmsFailed);
   GETFUNC(notifySmsDeleted);
   GETFUNC(notifySmsDeleteFailed);
+  GETFUNC(notifyNoMessageInList);
+  GETFUNC(notifyListCreated);
 #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/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -94,16 +94,18 @@ extern "C" {
     NS_EXPORT PRInt32 JNICALL Java_org_mozilla_gecko_GeckoAppShell_saveMessageInSentbox(JNIEnv* jenv, jclass, jstring, jstring, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsSent(JNIEnv* jenv, jclass, jint, jstring, jstring, jlong, jint, jlong);
     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);
 
 #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
 }
 
 
@@ -631,16 +633,28 @@ Java_org_mozilla_gecko_GeckoAppShell_not
     };
 
 
     nsCOMPtr<nsIRunnable> runnable =
       new NotifySmsDeleteFailedRunnable(SmsRequest::ErrorType(aError), aRequestId, aProcessId);
     NS_DispatchToMainThread(runnable);
 }
 
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_notifyNoMessageInList(JNIEnv* jenv, jclass, jint, jlong)
+{
+  // TODO: implement
+}
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_notifyListCreated(JNIEnv* jenv, jclass, jint, jint, jstring, jstring, jstring, jlong, jint, jlong)
+{
+  // TODO: implement
+}
+
 #ifdef MOZ_JAVA_COMPOSITOR
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass)
 {
     nsWindow::BindToTexture();
 }