Merge "Remove our copy of the f_mtp.h kernel header, now that it is in bionic."
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 441370a..c0226f8 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1047,6 +1047,7 @@
closeClosable();
// finalize ALL statements queued up so far
closePendingStatements();
+ releaseCustomFunctions();
// close this database instance - regardless of its reference count value
dbclose();
if (mConnectionPool != null) {
@@ -1083,6 +1084,54 @@
private native void dbclose();
/**
+ * A callback interface for a custom sqlite3 function.
+ * This can be used to create a function that can be called from
+ * sqlite3 database triggers.
+ * @hide
+ */
+ public interface CustomFunction {
+ public void callback(String[] args);
+ }
+
+ /**
+ * Registers a CustomFunction callback as a function that can be called from
+ * sqlite3 database triggers.
+ * @param name the name of the sqlite3 function
+ * @param numArgs the number of arguments for the function
+ * @param function callback to call when the function is executed
+ * @hide
+ */
+ public void addCustomFunction(String name, int numArgs, CustomFunction function) {
+ verifyDbIsOpen();
+ synchronized (mCustomFunctions) {
+ int ref = native_addCustomFunction(name, numArgs, function);
+ if (ref != 0) {
+ // save a reference to the function for cleanup later
+ mCustomFunctions.add(new Integer(ref));
+ } else {
+ throw new SQLiteException("failed to add custom function " + name);
+ }
+ }
+ }
+
+ private void releaseCustomFunctions() {
+ synchronized (mCustomFunctions) {
+ for (int i = 0; i < mCustomFunctions.size(); i++) {
+ Integer function = mCustomFunctions.get(i);
+ native_releaseCustomFunction(function.intValue());
+ }
+ mCustomFunctions.clear();
+ }
+ }
+
+ // list of CustomFunction references so we can clean up when the database closes
+ private final ArrayList<Integer> mCustomFunctions =
+ new ArrayList<Integer>();
+
+ private native int native_addCustomFunction(String name, int numArgs, CustomFunction function);
+ private native void native_releaseCustomFunction(int function);
+
+ /**
* Gets the database version.
*
* @return the database version
@@ -1959,12 +2008,17 @@
}
@Override
- protected void finalize() {
- if (isOpen()) {
- Log.e(TAG, "close() was never explicitly called on database '" +
- mPath + "' ", mStackTrace);
- closeClosable();
- onAllReferencesReleased();
+ protected void finalize() throws Throwable {
+ try {
+ if (isOpen()) {
+ Log.e(TAG, "close() was never explicitly called on database '" +
+ mPath + "' ", mStackTrace);
+ closeClosable();
+ onAllReferencesReleased();
+ releaseCustomFunctions();
+ }
+ } finally {
+ super.finalize();
}
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index a23a5a7..10f1d2b 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -289,6 +289,7 @@
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC1);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC2);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC3);
+ DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC4);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.NAME);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 5a92193..290b532 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -62,6 +62,7 @@
};
static jfieldID offset_db_handle;
+static jmethodID method_custom_function_callback;
static char *createStr(const char *path, short extra) {
int len = strlen(path) + extra;
@@ -458,6 +459,62 @@
}
}
+static void custom_function_callback(sqlite3_context * context, int argc, sqlite3_value ** argv) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (!env) {
+ LOGE("custom_function_callback cannot call into Java on this thread");
+ return;
+ }
+
+ // pack up the arguments into a string array
+ jobjectArray strArray = env->NewObjectArray(argc, env->FindClass("java/lang/String"), NULL);
+ if (!strArray) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return;
+ }
+ for (int i = 0; i < argc; i++) {
+ char* arg = (char *)sqlite3_value_text(argv[i]);
+ jobject obj = env->NewStringUTF(arg);
+ if (!obj) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return;
+ }
+ env->SetObjectArrayElement(strArray, i, obj);
+ env->DeleteLocalRef(obj);
+ }
+
+ // get global ref to CustomFunction object from our user data
+ jobject function = (jobject)sqlite3_user_data(context);
+ env->CallVoidMethod(function, method_custom_function_callback, strArray);
+}
+
+static jint native_addCustomFunction(JNIEnv* env, jobject object,
+ jstring name, jint numArgs, jobject function)
+{
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+ char const *nameStr = env->GetStringUTFChars(name, NULL);
+ jobject ref = env->NewGlobalRef(function);
+ LOGD("native_addCustomFunction %s ref: %d", nameStr, ref);
+ int err = sqlite3_create_function(handle, nameStr, numArgs, SQLITE_UTF8,
+ (void *)ref, custom_function_callback, NULL, NULL);
+ env->ReleaseStringUTFChars(name, nameStr);
+
+ if (err == SQLITE_OK)
+ return (int)ref;
+ else {
+ LOGE("sqlite3_create_function returned %d", err);
+ env->DeleteGlobalRef(ref);
+ throw_sqlite3_exception(env, handle);
+ return 0;
+ }
+}
+
+static void native_releaseCustomFunction(JNIEnv* env, jobject object, jint ref)
+{
+ LOGD("native_releaseCustomFunction %d", ref);
+ env->DeleteGlobalRef((jobject)ref);
+}
+
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
@@ -472,6 +529,10 @@
{"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
{"releaseMemory", "()I", (void *)native_releaseMemory},
{"native_finalize", "(I)V", (void *)native_finalize},
+ {"native_addCustomFunction",
+ "(Ljava/lang/String;ILandroid/database/sqlite/SQLiteDatabase$CustomFunction;)I",
+ (void *)native_addCustomFunction},
+ {"native_releaseCustomFunction", "(I)V", (void *)native_releaseCustomFunction},
};
int register_android_database_SQLiteDatabase(JNIEnv *env)
@@ -490,6 +551,17 @@
return -1;
}
+ clazz = env->FindClass("android/database/sqlite/SQLiteDatabase$CustomFunction");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/sqlite/SQLiteDatabase$CustomFunction\n");
+ return -1;
+ }
+ method_custom_function_callback = env->GetMethodID(clazz, "callback", "([Ljava/lang/String;)V");
+ if (method_custom_function_callback == NULL) {
+ LOGE("Can't find method SQLiteDatabase.CustomFunction.callback\n");
+ return -1;
+ }
+
return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase",
sMethods, NELEM(sMethods));
}
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 46d7493..62f824f 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -2,6 +2,9 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
test_src_files := \
InputChannel_test.cpp \
InputDispatcher_test.cpp \
@@ -43,3 +46,5 @@
# Build the manual test programs.
include $(call all-subdir-makefiles)
+
+endif
\ No newline at end of file
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index f1b8cd5..b9f206a 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -2,6 +2,9 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
test_src_files := \
ObbFile_test.cpp \
PollLoop_test.cpp
@@ -37,3 +40,5 @@
$(eval LOCAL_MODULE_TAGS := $(module_tags)) \
$(eval include $(BUILD_EXECUTABLE)) \
)
+
+endif
\ No newline at end of file