Merge "More cleanup of Loader APIs."
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index a026eca..9a8f2d2 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -16,6 +16,7 @@
 
 package android.database;
 
+import android.content.res.Resources;
 import android.database.sqlite.SQLiteClosable;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -25,6 +26,13 @@
  * A buffer containing multiple cursor rows.
  */
 public class CursorWindow extends SQLiteClosable implements Parcelable {
+    /** The cursor window size. resource xml file specifies the value in kB.
+     * convert it to bytes here by multiplying with 1024.
+     */
+    private static final int sCursorWindowSize =
+        Resources.getSystem().getInteger(
+                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+
     /** The pointer to the native window class */
     @SuppressWarnings("unused")
     private int nWindow;
@@ -38,7 +46,7 @@
      */
     public CursorWindow(boolean localWindow) {
         mStartPos = 0;
-        native_init(localWindow);
+        native_init(sCursorWindowSize, localWindow);
     }
 
     /**
@@ -574,7 +582,7 @@
     private native IBinder native_getBinder();
 
     /** Does the native side initialization for an empty window */
-    private native void native_init(boolean localOnly);
+    private native void native_init(int cursorWindowSize, boolean localOnly);
 
     /** Does the native side initialization with an existing binder from another process */
     private native void native_init(IBinder nativeBinder);
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 184988b..7d1f175 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -18,6 +18,7 @@
 
 import android.app.AppGlobals;
 import android.content.ContentValues;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.DatabaseUtils;
@@ -2670,4 +2671,22 @@
      * @param statementId statement to be finzlied by sqlite
      */
     private final native void native_finalize(int statementId);
+
+    /**
+     * set sqlite soft heap limit
+     * http://www.sqlite.org/c3ref/soft_heap_limit64.html
+     */
+
+    /** sqlite soft heap limit http://www.sqlite.org/c3ref/soft_heap_limit64.html
+     * set it to 4 times the default cursor window size.
+     * TODO what is an appropriate value, considring the WAL feature which could burn
+     * a lot of memory with many connections to the database. needs testing to figure out
+     * optimal value for this.
+     */
+    static {
+        int limit = Resources.getSystem().getInteger(
+                com.android.internal.R.integer.config_cursorWindowSize) * 1024 * 4;
+        native_setSqliteSoftHeapLimit(limit);
+    }
+    private final static native void native_setSqliteSoftHeapLimit(int softHeapLimit);
 }
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index fad9539..c4cd2a6 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -50,13 +50,14 @@
     return GET_WINDOW(env, javaWindow);
 }
 
-static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly)
+static void native_init_empty(JNIEnv * env, jobject object, jint cursorWindowSize,
+        jboolean localOnly)
 {
     uint8_t * data;
     size_t size;
     CursorWindow * window;
 
-    window = new CursorWindow(MAX_WINDOW_SIZE);
+    window = new CursorWindow(cursorWindowSize);
     if (!window) {
         jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object");
         return;
@@ -614,7 +615,7 @@
 static JNINativeMethod sMethods[] =
 {
      /* name, signature, funcPtr */
-    {"native_init", "(Z)V", (void *)native_init_empty},
+    {"native_init", "(IZ)V", (void *)native_init_empty},
     {"native_init", "(Landroid/os/IBinder;)V", (void *)native_init_memory},
     {"native_getBinder", "()Landroid/os/IBinder;", (void *)native_getBinder},
     {"native_clear", "()V", (void *)native_clear},
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 7aeed98..9fd40c0 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -46,7 +46,6 @@
 
 #define UTF16_STORAGE 0
 #define INVALID_VERSION -1
-#define SQLITE_SOFT_HEAP_LIMIT (4 * 1024 * 1024)
 #define ANDROID_TABLE "android_metadata"
 /* uncomment the next line to force-enable logging of all statements */
 // #define DB_LOG_STATEMENTS
@@ -66,6 +65,7 @@
 static jfieldID offset_db_handle;
 static jmethodID method_custom_function_callback;
 static jclass string_class = NULL;
+static jint sSqliteSoftHeapLimit = 0;
 
 static char *createStr(const char *path, short extra) {
     int len = strlen(path) + extra;
@@ -129,7 +129,7 @@
     // The soft heap limit prevents the page cache allocations from growing
     // beyond the given limit, no matter what the max page cache sizes are
     // set to. The limit does not, as of 3.5.0, affect any other allocations.
-    sqlite3_soft_heap_limit(SQLITE_SOFT_HEAP_LIMIT);
+    sqlite3_soft_heap_limit(sSqliteSoftHeapLimit);
 
     // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY
     err = sqlite3_busy_timeout(handle, 1000 /* ms */);
@@ -379,10 +379,14 @@
     if (meta != NULL) sqlite3_free_table(meta);
 }
 
+static void native_setSqliteSoftHeapLimit(JNIEnv* env, jobject object, jint limit) {
+    sSqliteSoftHeapLimit = limit;
+}
+
 static jint native_releaseMemory(JNIEnv *env, jobject clazz)
 {
     // Attempt to release as much memory from the
-    return sqlite3_release_memory(SQLITE_SOFT_HEAP_LIMIT);
+    return sqlite3_release_memory(sSqliteSoftHeapLimit);
 }
 
 static void native_finalize(JNIEnv* env, jobject object, jint statementId)
@@ -466,6 +470,7 @@
     {"enableSqlProfiling", "(Ljava/lang/String;S)V", (void *)enableSqlProfiling},
     {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
     {"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
+    {"native_setSqliteSoftHeapLimit", "(I)V", (void *)native_setSqliteSoftHeapLimit},
     {"releaseMemory", "()I", (void *)native_releaseMemory},
     {"native_finalize", "(I)V", (void *)native_finalize},
     {"native_addCustomFunction",
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0d2d42f..0d840c2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -515,4 +515,7 @@
          Build.MODEL. The format string shall not be escaped. -->
     <string name="config_useragentprofile_url"></string>
 
+    <!-- When a database query is executed, the results retuned are paginated
+         in pages of size (in KB) indicated by this value -->
+    <integer name="config_cursorWindowSize">2048</integer>
 </resources>
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
index 4fbff2a..f0b2909 100644
--- a/include/binder/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -25,7 +25,6 @@
 #include <utils/RefBase.h>
 
 #define DEFAULT_WINDOW_SIZE 4096
-#define MAX_WINDOW_SIZE (1024 * 1024)
 #define WINDOW_ALLOCATION_SIZE 4096
 
 #define ROW_SLOT_CHUNK_NUM_ROWS 16