Fixed bug 1573 - SDL does not support system clipboard on Android.
authorSam Lantinga <slouken@libsdl.org>
Wed, 26 Sep 2012 20:14:37 -0700
changeset 6464 ab55284b389f
parent 6463 051403ca44cc
child 6465 09b96f7ebe80
Fixed bug 1573 - SDL does not support system clipboard on Android. Philipp Wiesemann 2012-08-18 14:09:47 PDT there is currently no way in SDL to interact with the system clipboard on Android. I attached a patch which tries to implement the three clipboard functions for Android. It does not add the CLIPBOARDUPDATE event because this seems to require Android API 11 or polling.
src/core/android/SDL_android.cpp
src/core/android/SDL_android.h
src/video/android/SDL_androidclipboard.c
src/video/android/SDL_androidclipboard.h
src/video/android/SDL_androidvideo.c
--- a/src/core/android/SDL_android.cpp	Wed Sep 26 15:57:28 2012 -0300
+++ b/src/core/android/SDL_android.cpp	Wed Sep 26 20:14:37 2012 -0700
@@ -735,6 +735,84 @@
     return Android_JNI_FileClose(ctx, true);
 }
 
+// returns a new global reference which needs to be released later
+static jobject Android_JNI_GetSystemServiceObject(const char* name)
+{
+    LocalReferenceHolder refs;
+    JNIEnv* env = Android_JNI_GetEnv();
+    if (!refs.init(env)) {
+        return NULL;
+    }
+
+    jstring service = env->NewStringUTF(name);
+
+    jmethodID mid;
+
+    mid = env->GetStaticMethodID(mActivityClass, "getContext", "()Landroid/content/Context;");
+    jobject context = env->CallStaticObjectMethod(mActivityClass, mid);
+
+    mid = env->GetMethodID(mActivityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+    jobject manager = env->CallObjectMethod(context, mid, service);
+
+    env->DeleteLocalRef(service);
+
+    return manager ? env->NewGlobalRef(manager) : NULL;
+}
+
+#define SETUP_CLIPBOARD(error) \
+    LocalReferenceHolder refs; \
+    JNIEnv* env = Android_JNI_GetEnv(); \
+    if (!refs.init(env)) { \
+        return error; \
+    } \
+    jobject clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \
+    if (!clipboard) { \
+        return error; \
+    }
+
+extern "C" int Android_JNI_SetClipboardText(const char* text)
+{
+    SETUP_CLIPBOARD(-1)
+
+    jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "setText", "(Ljava/lang/CharSequence;)V");
+    jstring string = env->NewStringUTF(text);
+    env->CallVoidMethod(clipboard, mid, string);
+    env->DeleteGlobalRef(clipboard);
+    env->DeleteLocalRef(string);
+    return 0;
+}
+
+extern "C" char* Android_JNI_GetClipboardText()
+{
+    SETUP_CLIPBOARD(SDL_strdup(""))
+
+    jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "getText", "()Ljava/lang/CharSequence;");
+    jobject sequence = env->CallObjectMethod(clipboard, mid);
+    env->DeleteGlobalRef(clipboard);
+    if (sequence) {
+        mid = env->GetMethodID(env->GetObjectClass(sequence), "toString", "()Ljava/lang/String;");
+        jstring string = reinterpret_cast<jstring>(env->CallObjectMethod(sequence, mid));
+        const char* utf = env->GetStringUTFChars(string, 0);
+        if (utf) {
+            char* text = SDL_strdup(utf);
+            env->ReleaseStringUTFChars(string, utf);
+            return text;
+        }
+    }
+    return SDL_strdup("");
+}
+
+extern "C" SDL_bool Android_JNI_HasClipboardText()
+{
+    SETUP_CLIPBOARD(SDL_FALSE)
+
+    jmethodID mid = env->GetMethodID(env->GetObjectClass(clipboard), "hasText", "()Z");
+    jboolean has = env->CallBooleanMethod(clipboard, mid);
+    env->DeleteGlobalRef(clipboard);
+    return has ? SDL_TRUE : SDL_FALSE;
+}
+
+
 // returns 0 on success or -1 on error (others undefined then)
 // returns truthy or falsy value in plugged, charged and battery
 // returns the value in seconds and percent or -1 if not available
--- a/src/core/android/SDL_android.h	Wed Sep 26 15:57:28 2012 -0300
+++ b/src/core/android/SDL_android.h	Wed Sep 26 20:14:37 2012 -0700
@@ -47,6 +47,11 @@
 size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, size_t size, size_t num);
 int Android_JNI_FileClose(SDL_RWops* ctx);
 
+/* Clipboard support */
+int Android_JNI_SetClipboardText(const char* text);
+char* Android_JNI_GetClipboardText();
+SDL_bool Android_JNI_HasClipboardText();
+
 /* Power support */
 int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/android/SDL_androidclipboard.c	Wed Sep 26 20:14:37 2012 -0700
@@ -0,0 +1,26 @@
+#include "SDL_config.h"
+
+#if SDL_VIDEO_DRIVER_ANDROID
+
+#include "SDL_androidvideo.h"
+
+#include "../../core/android/SDL_android.h"
+
+int
+Android_SetClipboardText(_THIS, const char *text)
+{
+	return Android_JNI_SetClipboardText(text);
+}
+
+char *
+Android_GetClipboardText(_THIS)
+{
+	return Android_JNI_GetClipboardText();
+}
+
+SDL_bool Android_HasClipboardText(_THIS)
+{
+	return Android_JNI_HasClipboardText();
+}
+
+#endif /* SDL_VIDEO_DRIVER_ANDROID */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/android/SDL_androidclipboard.h	Wed Sep 26 20:14:37 2012 -0700
@@ -0,0 +1,10 @@
+#include "SDL_config.h"
+
+#ifndef _SDL_androidclipboard_h
+#define _SDL_androidclipboard_h
+
+extern int Android_SetClipboardText(_THIS, const char *text);
+extern char *Android_GetClipboardText(_THIS);
+extern SDL_bool Android_HasClipboardText(_THIS);
+
+#endif /* _SDL_androidclipboard_h */
--- a/src/video/android/SDL_androidvideo.c	Wed Sep 26 15:57:28 2012 -0300
+++ b/src/video/android/SDL_androidvideo.c	Wed Sep 26 20:14:37 2012 -0700
@@ -33,6 +33,7 @@
 #include "../../events/SDL_windowevents_c.h"
 
 #include "SDL_androidvideo.h"
+#include "SDL_androidclipboard.h"
 #include "SDL_androidevents.h"
 #include "SDL_androidkeyboard.h"
 #include "SDL_androidwindow.h"
@@ -126,6 +127,11 @@
     device->SDL_ToggleScreenKeyboard = Android_ToggleScreenKeyboard;
     device->SDL_IsScreenKeyboardShown = Android_IsScreenKeyboardShown;
 
+    /* Clipboard */
+    device->SetClipboardText = Android_SetClipboardText;
+    device->GetClipboardText = Android_GetClipboardText;
+    device->HasClipboardText = Android_HasClipboardText;
+
     return device;
 }