Fixed bug 2266 - please add notifications for clipboard updates on Android
Sylvain Hi! here's a patch for that with two class loaded regarding API level. Test both case : before API 11 and after. I also remove now unused GetSystemServiceFromUIThread() and minor clean-up (haptic warning prototype).
parent
6885bc88bf
commit
fe21a74763
|
@ -63,6 +63,8 @@ public class SDLActivity extends Activity {
|
|||
protected static ViewGroup mLayout;
|
||||
protected static SDLJoystickHandler mJoystickHandler;
|
||||
protected static SDLHapticHandler mHapticHandler;
|
||||
protected static SDLClipboardHandler mClipboardHandler;
|
||||
|
||||
|
||||
// This is what SDL runs in. It invokes SDL_main(), eventually
|
||||
protected static Thread mSDLThread;
|
||||
|
@ -116,6 +118,7 @@ public class SDLActivity extends Activity {
|
|||
mLayout = null;
|
||||
mJoystickHandler = null;
|
||||
mHapticHandler = null;
|
||||
mClipboardHandler = null;
|
||||
mSDLThread = null;
|
||||
mAudioTrack = null;
|
||||
mAudioRecord = null;
|
||||
|
@ -187,6 +190,13 @@ public class SDLActivity extends Activity {
|
|||
}
|
||||
mHapticHandler = new SDLHapticHandler();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
mClipboardHandler = new SDLClipboardHandler_API11();
|
||||
} else {
|
||||
/* Before API 11, no clipboard notification (eg no SDL_CLIPBOARDUPDATE) */
|
||||
mClipboardHandler = new SDLClipboardHandler_Old();
|
||||
}
|
||||
|
||||
mLayout = new RelativeLayout(this);
|
||||
mLayout.addView(mSurface);
|
||||
|
||||
|
@ -498,6 +508,7 @@ public class SDLActivity extends Activity {
|
|||
int action, float x,
|
||||
float y, float p);
|
||||
public static native void onNativeAccel(float x, float y, float z);
|
||||
public static native void onNativeClipboardChanged();
|
||||
public static native void onNativeSurfaceChanged();
|
||||
public static native void onNativeSurfaceDestroyed();
|
||||
public static native int nativeAddJoystick(int device_id, String name,
|
||||
|
@ -607,35 +618,6 @@ public class SDLActivity extends Activity {
|
|||
return mSingleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
* @return result of getSystemService(name) but executed on UI thread.
|
||||
*/
|
||||
public Object getSystemServiceFromUiThread(final String name) {
|
||||
final Object lock = new Object();
|
||||
final Object[] results = new Object[2]; // array for writable variables
|
||||
synchronized (lock) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (lock) {
|
||||
results[0] = getSystemService(name);
|
||||
results[1] = Boolean.TRUE;
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (results[1] == null) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return results[0];
|
||||
}
|
||||
|
||||
static class ShowTextInputTask implements Runnable {
|
||||
/*
|
||||
* This is used to regulate the pan&scan method to have some offset from
|
||||
|
@ -1182,6 +1164,29 @@ public class SDLActivity extends Activity {
|
|||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static boolean clipboardHasText() {
|
||||
return mClipboardHandler.clipboardHasText();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static String clipboardGetText() {
|
||||
return mClipboardHandler.clipboardGetText();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void clipboardSetText(String string) {
|
||||
mClipboardHandler.clipboardSetText(string);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1993,3 +1998,86 @@ class SDLHapticHandler {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface SDLClipboardHandler {
|
||||
|
||||
public boolean clipboardHasText();
|
||||
public String clipboardGetText();
|
||||
public void clipboardSetText(String string);
|
||||
|
||||
}
|
||||
|
||||
|
||||
class SDLClipboardHandler_API11 implements
|
||||
SDLClipboardHandler,
|
||||
android.content.ClipboardManager.OnPrimaryClipChangedListener {
|
||||
|
||||
protected android.content.ClipboardManager mClipMgr;
|
||||
|
||||
SDLClipboardHandler_API11() {
|
||||
mClipMgr = (android.content.ClipboardManager) SDLActivity.mSingleton.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
mClipMgr.addPrimaryClipChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clipboardHasText() {
|
||||
return mClipMgr.hasText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String clipboardGetText() {
|
||||
CharSequence text;
|
||||
text = mClipMgr.getText();
|
||||
if (text != null) {
|
||||
return text.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clipboardSetText(String string) {
|
||||
mClipMgr.removePrimaryClipChangedListener(this);
|
||||
mClipMgr.setText(string);
|
||||
mClipMgr.addPrimaryClipChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrimaryClipChanged() {
|
||||
SDLActivity.onNativeClipboardChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SDLClipboardHandler_Old implements
|
||||
SDLClipboardHandler {
|
||||
|
||||
protected android.text.ClipboardManager mClipMgrOld;
|
||||
|
||||
SDLClipboardHandler_Old() {
|
||||
mClipMgrOld = (android.text.ClipboardManager) SDLActivity.mSingleton.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clipboardHasText() {
|
||||
return mClipMgrOld.hasText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String clipboardGetText() {
|
||||
CharSequence text;
|
||||
text = mClipMgrOld.getText();
|
||||
if (text != null) {
|
||||
return text.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clipboardSetText(String string) {
|
||||
mClipMgrOld.setText(string);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -91,6 +91,14 @@ JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveJoystick)(
|
|||
JNIEnv* env, jclass jcls,
|
||||
jint device_id);
|
||||
|
||||
JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddHaptic)(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint device_id, jstring device_name);
|
||||
|
||||
JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveHaptic)(
|
||||
JNIEnv* env, jclass jcls,
|
||||
jint device_id);
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(
|
||||
JNIEnv* env, jclass jcls);
|
||||
|
||||
|
@ -121,6 +129,9 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)(
|
|||
JNIEnv* env, jclass jcls,
|
||||
jfloat x, jfloat y, jfloat z);
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
|
||||
JNIEnv* env, jclass jcls);
|
||||
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
|
||||
JNIEnv* env, jclass cls);
|
||||
|
||||
|
@ -187,7 +198,10 @@ static jmethodID midInputGetInputDeviceIds;
|
|||
static jmethodID midSendMessage;
|
||||
static jmethodID midShowTextInput;
|
||||
static jmethodID midIsScreenKeyboardShown;
|
||||
static jmethodID midGetSystemServiceFromUiThread;
|
||||
static jmethodID midClipboardSetText;
|
||||
static jmethodID midClipboardGetText;
|
||||
static jmethodID midClipboardHasText;
|
||||
|
||||
|
||||
/* static fields */
|
||||
static jfieldID fidSeparateMouseAndTouch;
|
||||
|
@ -269,8 +283,12 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls)
|
|||
"showTextInput", "(IIII)Z");
|
||||
midIsScreenKeyboardShown = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||
"isScreenKeyboardShown","()Z");
|
||||
midGetSystemServiceFromUiThread = (*mEnv)->GetMethodID(mEnv, mActivityClass,
|
||||
"getSystemServiceFromUiThread", "(Ljava/lang/String;)Ljava/lang/Object;");
|
||||
midClipboardSetText = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||
"clipboardSetText", "(Ljava/lang/String;)V");
|
||||
midClipboardGetText = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||
"clipboardGetText", "()Ljava/lang/String;");
|
||||
midClipboardHasText = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
|
||||
"clipboardHasText", "()Z");
|
||||
|
||||
bHasNewData = SDL_FALSE;
|
||||
|
||||
|
@ -279,7 +297,8 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls)
|
|||
!midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose ||
|
||||
!midPollInputDevices || !midPollHapticDevices || !midHapticRun ||
|
||||
!midSetActivityTitle || !midSetOrientation || !midGetContext || !midInputGetInputDeviceIds ||
|
||||
!midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown || !midGetSystemServiceFromUiThread) {
|
||||
!midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown ||
|
||||
!midClipboardSetText || !midClipboardGetText || !midClipboardHasText) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
|
||||
}
|
||||
|
||||
|
@ -366,7 +385,7 @@ JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveJoystick)(
|
|||
return Android_RemoveJoystick(device_id);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_nativeAddHaptic(
|
||||
JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddHaptic)(
|
||||
JNIEnv* env, jclass jcls, jint device_id, jstring device_name)
|
||||
{
|
||||
int retval;
|
||||
|
@ -379,7 +398,7 @@ JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_nativeAddHaptic(
|
|||
return retval;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_nativeRemoveHaptic(
|
||||
JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveHaptic)(
|
||||
JNIEnv* env, jclass jcls, jint device_id)
|
||||
{
|
||||
return Android_RemoveHaptic(device_id);
|
||||
|
@ -492,6 +511,13 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)(
|
|||
bHasNewData = SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Clipboard */
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
|
||||
JNIEnv* env, jclass jcls)
|
||||
{
|
||||
SDL_SendClipboardUpdate();
|
||||
}
|
||||
|
||||
/* Low memory */
|
||||
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
|
||||
JNIEnv* env, jclass cls)
|
||||
|
@ -1363,118 +1389,41 @@ int Android_JNI_FileClose(SDL_RWops* ctx)
|
|||
return Internal_Android_JNI_FileClose(ctx, SDL_TRUE);
|
||||
}
|
||||
|
||||
/* returns a new global reference which needs to be released later */
|
||||
static jobject Android_JNI_GetSystemServiceObject(const char* name)
|
||||
{
|
||||
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
|
||||
JNIEnv* env = Android_JNI_GetEnv();
|
||||
jobject retval = NULL;
|
||||
jstring service;
|
||||
jobject context;
|
||||
jobject manager;
|
||||
|
||||
if (!LocalReferenceHolder_Init(&refs, env)) {
|
||||
LocalReferenceHolder_Cleanup(&refs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
service = (*env)->NewStringUTF(env, name);
|
||||
|
||||
/* context = SDLActivity.getContext(); */
|
||||
context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
|
||||
|
||||
manager = (*env)->CallObjectMethod(env, context, midGetSystemServiceFromUiThread, service);
|
||||
|
||||
(*env)->DeleteLocalRef(env, service);
|
||||
|
||||
retval = manager ? (*env)->NewGlobalRef(env, manager) : NULL;
|
||||
LocalReferenceHolder_Cleanup(&refs);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define SETUP_CLIPBOARD(error) \
|
||||
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); \
|
||||
JNIEnv* env = Android_JNI_GetEnv(); \
|
||||
jobject clipboard; \
|
||||
if (!LocalReferenceHolder_Init(&refs, env)) { \
|
||||
LocalReferenceHolder_Cleanup(&refs); \
|
||||
return error; \
|
||||
} \
|
||||
clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \
|
||||
if (!clipboard) { \
|
||||
LocalReferenceHolder_Cleanup(&refs); \
|
||||
return error; \
|
||||
}
|
||||
|
||||
#define CLEANUP_CLIPBOARD() \
|
||||
LocalReferenceHolder_Cleanup(&refs);
|
||||
|
||||
int Android_JNI_SetClipboardText(const char* text)
|
||||
{
|
||||
/* Watch out for C89 scoping rules because of the macro */
|
||||
SETUP_CLIPBOARD(-1)
|
||||
|
||||
/* Nest the following in a scope to avoid C89 declaration rules triggered by the macro */
|
||||
{
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "setText", "(Ljava/lang/CharSequence;)V");
|
||||
jstring string = (*env)->NewStringUTF(env, text);
|
||||
(*env)->CallVoidMethod(env, clipboard, mid, string);
|
||||
(*env)->DeleteGlobalRef(env, clipboard);
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
}
|
||||
CLEANUP_CLIPBOARD();
|
||||
|
||||
JNIEnv* env = Android_JNI_GetEnv();
|
||||
jstring string = (*env)->NewStringUTF(env, text);
|
||||
(*env)->CallStaticVoidMethod(env, mActivityClass, midClipboardSetText, string);
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* Android_JNI_GetClipboardText(void)
|
||||
{
|
||||
/* Watch out for C89 scoping rules because of the macro */
|
||||
SETUP_CLIPBOARD(SDL_strdup(""))
|
||||
|
||||
/* Nest the following in a scope to avoid C89 declaration rules triggered by the macro */
|
||||
{
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "getText", "()Ljava/lang/CharSequence;");
|
||||
jobject sequence = (*env)->CallObjectMethod(env, clipboard, mid);
|
||||
(*env)->DeleteGlobalRef(env, clipboard);
|
||||
if (sequence) {
|
||||
jstring string;
|
||||
const char* utf;
|
||||
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, sequence), "toString", "()Ljava/lang/String;");
|
||||
string = (jstring)((*env)->CallObjectMethod(env, sequence, mid));
|
||||
utf = (*env)->GetStringUTFChars(env, string, 0);
|
||||
if (utf) {
|
||||
char* text = SDL_strdup(utf);
|
||||
(*env)->ReleaseStringUTFChars(env, string, utf);
|
||||
|
||||
CLEANUP_CLIPBOARD();
|
||||
|
||||
return text;
|
||||
}
|
||||
JNIEnv* env = Android_JNI_GetEnv();
|
||||
char* text = NULL;
|
||||
jstring string;
|
||||
|
||||
string = (*env)->CallStaticObjectMethod(env, mActivityClass, midClipboardGetText);
|
||||
if (string) {
|
||||
const char* utf = (*env)->GetStringUTFChars(env, string, 0);
|
||||
if (utf) {
|
||||
text = SDL_strdup(utf);
|
||||
(*env)->ReleaseStringUTFChars(env, string, utf);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, string);
|
||||
}
|
||||
CLEANUP_CLIPBOARD();
|
||||
|
||||
return SDL_strdup("");
|
||||
|
||||
return (text == NULL) ? SDL_strdup("") : text;
|
||||
}
|
||||
|
||||
SDL_bool Android_JNI_HasClipboardText(void)
|
||||
{
|
||||
jmethodID mid;
|
||||
jboolean has;
|
||||
/* Watch out for C89 scoping rules because of the macro */
|
||||
SETUP_CLIPBOARD(SDL_FALSE)
|
||||
|
||||
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "hasText", "()Z");
|
||||
has = (*env)->CallBooleanMethod(env, clipboard, mid);
|
||||
(*env)->DeleteGlobalRef(env, clipboard);
|
||||
|
||||
CLEANUP_CLIPBOARD();
|
||||
|
||||
return has ? SDL_TRUE : SDL_FALSE;
|
||||
JNIEnv* env = Android_JNI_GetEnv();
|
||||
jboolean retval = (*env)->CallStaticBooleanMethod(env, mActivityClass, midClipboardHasText);
|
||||
return (retval == JNI_TRUE) ? 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
|
||||
|
|
Loading…
Reference in New Issue