From 539c3330a8dd4a0d47e3b422bf527a4d4f6a22e5 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Tue, 2 Oct 2018 14:57:48 +0100 Subject: ANDROID: Implement clipboard support --- backends/platform/android/android.cpp | 15 +++- backends/platform/android/android.h | 3 + backends/platform/android/jni.cpp | 80 +++++++++++++++++++++- backends/platform/android/jni.h | 8 +++ .../android/org/scummvm/scummvm/ScummVM.java | 4 ++ .../org/scummvm/scummvm/ScummVMActivity.java | 41 +++++++++++ 6 files changed, 149 insertions(+), 2 deletions(-) (limited to 'backends/platform') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 691114e9e3..461b863df8 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -405,7 +405,8 @@ bool OSystem_Android::hasFeature(Feature f) { f == kFeatureVirtualKeyboard || f == kFeatureOverlaySupportsAlpha || f == kFeatureOpenUrl || - f == kFeatureTouchpadMode); + f == kFeatureTouchpadMode || + f == kFeatureClipboardSupport); } void OSystem_Android::setFeatureState(Feature f, bool enable) { @@ -600,6 +601,18 @@ bool OSystem_Android::openUrl(const Common::String &url) { return JNI::openUrl(url.c_str()); } +bool OSystem_Android::hasTextInClipboard() { + return JNI::hasTextInClipboard(); +} + +Common::String OSystem_Android::getTextFromClipboard() { + return JNI::getTextFromClipboard(); +} + +bool OSystem_Android::setTextInClipboard(const Common::String &text) { + return JNI::setTextInClipboard(text); +} + Common::String OSystem_Android::getSystemProperty(const char *name) const { char value[PROP_VALUE_MAX]; diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 3a9d391ea9..61715daeb4 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -286,6 +286,9 @@ public: virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); virtual bool openUrl(const Common::String &url); + virtual bool hasTextInClipboard(); + virtual Common::String getTextFromClipboard(); + virtual bool setTextInClipboard(const Common::String &text); virtual Common::String getSystemLanguage() const; }; diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 256ae09ef8..3b84726dbd 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -45,6 +45,7 @@ #include "common/config-manager.h" #include "common/error.h" #include "common/textconsole.h" +#include "common/translation.h" #include "engines/engine.h" #include "backends/platform/android/android.h" @@ -77,6 +78,9 @@ bool JNI::_ready_for_events = 0; jmethodID JNI::_MID_getDPI = 0; jmethodID JNI::_MID_displayMessageOnOSD = 0; jmethodID JNI::_MID_openUrl = 0; +jmethodID JNI::_MID_hasTextInClipboard = 0; +jmethodID JNI::_MID_getTextFromClipboard = 0; +jmethodID JNI::_MID_setTextInClipboard = 0; jmethodID JNI::_MID_isConnectionLimited = 0; jmethodID JNI::_MID_setWindowCaption = 0; jmethodID JNI::_MID_showVirtualKeyboard = 0; @@ -109,7 +113,9 @@ const JNINativeMethod JNI::_natives[] = { { "enableZoning", "(Z)V", (void *)JNI::enableZoning }, { "setPause", "(Z)V", - (void *)JNI::setPause } + (void *)JNI::setPause }, + { "getCurrentCharset", "()Ljava/lang/String;", + (void *)JNI::getCurrentCharset } }; JNI::JNI() { @@ -253,6 +259,66 @@ bool JNI::openUrl(const char *url) { return success; } +bool JNI::hasTextInClipboard() { + bool hasText = false; + JNIEnv *env = JNI::getEnv(); + hasText = env->CallBooleanMethod(_jobj, _MID_hasTextInClipboard); + + if (env->ExceptionCheck()) { + LOGE("Failed to check the contents of the clipboard"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + hasText = true; + } + + return hasText; +} + +Common::String JNI::getTextFromClipboard() { + JNIEnv *env = JNI::getEnv(); + + jbyteArray javaText = (jbyteArray)env->CallObjectMethod(_jobj, _MID_getTextFromClipboard); + + if (env->ExceptionCheck()) { + LOGE("Failed to retrieve text from the clipboard"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return Common::String(); + } + + int len = env->GetArrayLength(javaText); + char* buf = new char[len]; + env->GetByteArrayRegion(javaText, 0, len, reinterpret_cast(buf)); + Common::String text(buf, len); + delete[] buf; + + return text; +} + +bool JNI::setTextInClipboard(const Common::String &text) { + bool success = true; + JNIEnv *env = JNI::getEnv(); + + jbyteArray javaText = env->NewByteArray(text.size()); + env->SetByteArrayRegion(javaText, 0, text.size(), reinterpret_cast(text.c_str())); + + success = env->CallBooleanMethod(_jobj, _MID_setTextInClipboard, javaText); + + if (env->ExceptionCheck()) { + LOGE("Failed to add text to the clipboard"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + success = false; + } + + env->DeleteLocalRef(javaText); + return success; +} + bool JNI::isConnectionLimited() { bool limited = false; JNIEnv *env = JNI::getEnv(); @@ -449,6 +515,9 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, FIND_METHOD(, getDPI, "([F)V"); FIND_METHOD(, displayMessageOnOSD, "(Ljava/lang/String;)V"); FIND_METHOD(, openUrl, "(Ljava/lang/String;)V"); + FIND_METHOD(, hasTextInClipboard, "()Z"); + FIND_METHOD(, getTextFromClipboard, "()[B"); + FIND_METHOD(, setTextInClipboard, "([B)Z"); FIND_METHOD(, isConnectionLimited, "()Z"); FIND_METHOD(, showVirtualKeyboard, "(Z)V"); FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;"); @@ -611,4 +680,13 @@ void JNI::setPause(JNIEnv *env, jobject self, jboolean value) { } } +jstring JNI::getCurrentCharset(JNIEnv *env, jobject self) { +#ifdef USE_TRANSLATION + if (TransMan.getCurrentCharset() != "ASCII") { + return env->NewStringUTF(TransMan.getCurrentCharset().c_str()); + } +#endif + return env->NewStringUTF("ISO-8859-1"); +} + #endif diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 0798db448a..b88155f8b6 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -59,6 +59,9 @@ public: static void getDPI(float *values); static void displayMessageOnOSD(const char *msg); static bool openUrl(const char *url); + static bool hasTextInClipboard(); + static Common::String getTextFromClipboard(); + static bool setTextInClipboard(const Common::String &text); static bool isConnectionLimited(); static void showVirtualKeyboard(bool enable); static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); @@ -92,6 +95,9 @@ private: static jmethodID _MID_getDPI; static jmethodID _MID_displayMessageOnOSD; static jmethodID _MID_openUrl; + static jmethodID _MID_hasTextInClipboard; + static jmethodID _MID_getTextFromClipboard; + static jmethodID _MID_setTextInClipboard; static jmethodID _MID_isConnectionLimited; static jmethodID _MID_setWindowCaption; static jmethodID _MID_showVirtualKeyboard; @@ -127,6 +133,8 @@ private: static void enableZoning(JNIEnv *env, jobject self, jboolean enable); static void setPause(JNIEnv *env, jobject self, jboolean value); + + static jstring getCurrentCharset(JNIEnv *env, jobject self); }; inline bool JNI::haveSurface() { diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java index 47dcb32b22..163b50f42d 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java @@ -49,11 +49,15 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { // Feed an event to ScummVM. Safe to call from other threads. final public native void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5); + final public native String getCurrentCharset(); // Callbacks from C++ peer instance abstract protected void getDPI(float[] values); abstract protected void displayMessageOnOSD(String msg); abstract protected void openUrl(String url); + abstract protected boolean hasTextInClipboard(); + abstract protected byte[] getTextFromClipboard(); + abstract protected boolean setTextInClipboard(byte[] text); abstract protected boolean isConnectionLimited(); abstract protected void setWindowCaption(String caption); abstract protected void showVirtualKeyboard(boolean enable); diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java index 225496ca0d..58af703d56 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java @@ -12,6 +12,7 @@ import android.net.wifi.WifiInfo; import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.text.ClipboardManager; import android.util.DisplayMetrics; import android.util.Log; import android.view.SurfaceView; @@ -27,6 +28,8 @@ public class ScummVMActivity extends Activity { /* Establish whether the hover events are available */ private static boolean _hoverAvailable; + private ClipboardManager _clipboard; + static { try { MouseHelper.checkHoverAvailable(); // this throws exception if we're on too old version @@ -83,6 +86,42 @@ public class ScummVMActivity extends Activity { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); } + @Override + protected boolean hasTextInClipboard() { + return _clipboard.hasText(); + } + + @Override + protected byte[] getTextFromClipboard() { + CharSequence text = _clipboard.getText(); + if (text != null) { + String encoding = getCurrentCharset(); + byte[] out; + Log.d(LOG_TAG, String.format("Converting from UTF-8 to %s", encoding)); + try { + out = text.toString().getBytes(encoding); + } catch (java.io.UnsupportedEncodingException e) { + out = text.toString().getBytes(); + } + return out; + } + return null; + } + + @Override + protected boolean setTextInClipboard(byte[] text) { + String encoding = getCurrentCharset(); + String out; + Log.d(LOG_TAG, String.format("Converting from %s to UTF-8", encoding)); + try { + out = new String(text, encoding); + } catch (java.io.UnsupportedEncodingException e) { + out = new String(text); + } + _clipboard.setText(out); + return true; + } + @Override protected boolean isConnectionLimited() { WifiManager wifiMgr = (WifiManager)getSystemService(Context.WIFI_SERVICE); @@ -167,6 +206,8 @@ public class ScummVMActivity extends Activity { savePath = getDir("saves", MODE_WORLD_READABLE).getPath(); } + _clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE); + // Start ScummVM _scummvm = new MyScummVM(main_surface.getHolder()); -- cgit v1.2.3