android/lib/src/main/cpp/androidapp.cpp | 42 +++ android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java | 124 ++++++---- loleaflet/src/control/Control.JSDialogBuilder.js | 2 loleaflet/src/map/Map.js | 2 4 files changed, 126 insertions(+), 44 deletions(-)
New commits: commit 76114dd957e8f121969dd206213b3a31a4de7afc Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Wed Dec 18 17:10:04 2019 +0000 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Thu Dec 19 01:19:08 2019 +0100 android: improved native copy/paste. don't do copy/paste in the JS if we can avoid it. support text & html for cut / copy and share code. inject our own origin cookie to allow local short-circuiting. Change-Id: I3187104e9602e86b50cf52d45a9277db44ca8b3b Reviewed-on: https://gerrit.libreoffice.org/85455 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Jan Holesovsky <ke...@collabora.com> diff --git a/android/lib/src/main/cpp/androidapp.cpp b/android/lib/src/main/cpp/androidapp.cpp index d964d3579..577df5a90 100644 --- a/android/lib/src/main/cpp/androidapp.cpp +++ b/android/lib/src/main/cpp/androidapp.cpp @@ -333,11 +333,47 @@ Java_org_libreoffice_androidlib_LOActivity_saveAs(JNIEnv *env, jobject instance, env->ReleaseStringUTFChars(format_, format); } +static jstring tojstringAndFree(JNIEnv *env, char *str) +{ + if (!str) + return env->NewStringUTF(""); + jstring ret = env->NewStringUTF(str); + free(str); + return ret; +} + extern "C" -JNIEXPORT jstring JNICALL -Java_org_libreoffice_androidlib_LOActivity_getTextSelection(JNIEnv *env, jobject instance) { +JNIEXPORT jobjectArray JNICALL +Java_org_libreoffice_androidlib_LOActivity_getClipboardContent(JNIEnv *env, jobject instance) +{ + const char *mimeTypes[] = { "text/plain;charset=utf-8", "text/html", nullptr }; + size_t outCount = 0; + char **outMimeTypes = nullptr; + size_t *outSizes = nullptr; + char **outStreams = nullptr; + + jobjectArray values = (jobjectArray)env->NewObjectArray(2,env->FindClass("java/lang/String"),env->NewStringUTF("")); + + if (getLOKDocument()->getClipboard(mimeTypes, + &outCount, &outMimeTypes, + &outSizes, &outStreams)) + { + if (outCount != 2) + LOG_DBG("clipboard fetch produced wrong results"); + else + { + env->SetObjectArrayElement(values,0,tojstringAndFree(env, outStreams[0])); + env->SetObjectArrayElement(values,1,tojstringAndFree(env, outStreams[1])); + free (outMimeTypes[0]); + free (outMimeTypes[1]); + free (outMimeTypes); + free (outStreams); + } + } + else + LOG_DBG("failed to fetch mime-types"); - return env->NewStringUTF(getLOKDocument()->getTextSelection("text/plain;charset=utf-8")); + return values; } extern "C" diff --git a/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java b/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java index e1efc01f9..713032122 100644 --- a/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java +++ b/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java @@ -78,6 +78,9 @@ public class LOActivity extends AppCompatActivity { private int providerId; + /// Unique number identifying this app + document. + private long loadDocumentMillis = 0; + @Nullable private URI documentUri; @@ -478,6 +481,8 @@ public class LOActivity extends AppCompatActivity { mWebView.loadUrl(finalUrlToLoad); documentLoaded = true; + + loadDocumentMillis = android.os.SystemClock.uptimeMillis(); } static { @@ -564,46 +569,13 @@ public class LOActivity extends AppCompatActivity { case "uno": switch (messageAndParam[1]) { case ".uno:Paste": - clipData = clipboardManager.getPrimaryClip(); - if (clipData != null) { - if (clipData.getDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { - final ClipData.Item clipItem = clipData.getItemAt(0); - nativeHandler.post(new Runnable() { - @Override - public void run() { - LOActivity.this.paste("text/plain;charset=utf-16", clipItem.getText().toString()); - } - }); - } - return false; - } + return performPaste(); + case ".uno:Copy": + case ".uno:Cut": + populateClipboard(); break; - case ".uno:Copy": { - nativeHandler.post(new Runnable() { - @Override - public void run() { - String tempSelectedText = LOActivity.this.getTextSelection(); - if (!tempSelectedText.equals("")) { - clipData = ClipData.newPlainText(ClipDescription.MIMETYPE_TEXT_PLAIN, tempSelectedText); - clipboardManager.setPrimaryClip(clipData); - } - } - }); + default: break; - } - case ".uno:Cut": { - nativeHandler.post(new Runnable() { - @Override - public void run() { - String tempSelectedText = LOActivity.this.getTextSelection(); - if (!tempSelectedText.equals("")) { - clipData = ClipData.newPlainText(ClipDescription.MIMETYPE_TEXT_PLAIN, tempSelectedText); - clipboardManager.setPrimaryClip(clipData); - } - } - }); - break; - } } break; case "DIM_SCREEN": { @@ -671,9 +643,83 @@ public class LOActivity extends AppCompatActivity { public native void saveAs(String fileUri, String format); - public native String getTextSelection(); + public native String[] getClipboardContent(); public native void paste(String mimeType, String data); + + /// Returns a magic that specifies this application - and this document. + private final String getClipboardMagic() { + return "lool-clip-magic-4a22437e49a8-" + Long.toString(loadDocumentMillis); + } + + /// Needs to be executed after the .uno:Copy / Paste has executed + public final void populateClipboard() + { + /// FIXME: in theory we can do better with URIs to temporary files and so on... + nativeHandler.post(new Runnable() { + @Override + public void run() { + // text[0], html[1] + String[] clipStrings = LOActivity.this.getClipboardContent(); + if (clipStrings.length < 2 || + (clipStrings[0].length() == 0 && clipStrings[1].length() == 0)) + Log.e(TAG, "no clipboard to copy"); + else + { + String text = clipStrings[0]; + String html = clipStrings[1]; + + int idx = html.indexOf("<meta name=\"generator\" content=\""); + if (idx < 0) + idx = html.indexOf("<meta http-equiv=\"content-type\" content=\"text/html;"); + if (idx >= 0) { // inject our magic + StringBuffer newHtml = new StringBuffer(html); + newHtml.insert(idx, "<meta name=\"origin\" content=\"" + getClipboardMagic() + "\"/>\n"); + html = newHtml.toString(); + } + + if (text == null || text.length() == 0) + Log.i(TAG, "set text to clipoard with: text '" + text + "' and html '" + html + "'"); + clipData = ClipData.newHtmlText(ClipDescription.MIMETYPE_TEXT_HTML, text, html); + clipboardManager.setPrimaryClip(clipData); + } + } + }); + } + + /// Do the paste, and return true if we should short-circuit the paste locally + private final boolean performPaste() + { + clipData = clipboardManager.getPrimaryClip(); + ClipDescription clipDesc = clipData != null ? clipData.getDescription() : null; + if (clipDesc != null) { + if (clipDesc.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML)) { + final String html = clipData.getItemAt(0).getHtmlText(); + if (html.contains(getClipboardMagic())) { + Log.i(TAG, "clipboard comes from us: short circuit it " + html); + return true; + } else { + Log.i(TAG, "foreign html '" + html + "'"); + nativeHandler.post(new Runnable() { + @Override + public void run() { + LOActivity.this.paste("text/html", html); + } + }); + } + } + else if (clipDesc.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { + final ClipData.Item clipItem = clipData.getItemAt(0); + nativeHandler.post(new Runnable() { + @Override + public void run() { + LOActivity.this.paste("text/plain;charset=utf-16", clipItem.getText().toString()); + } + }); + } + } + return false; + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/loleaflet/src/control/Control.JSDialogBuilder.js b/loleaflet/src/control/Control.JSDialogBuilder.js index 617a8d9d0..9d91807cd 100644 --- a/loleaflet/src/control/Control.JSDialogBuilder.js +++ b/loleaflet/src/control/Control.JSDialogBuilder.js @@ -1444,7 +1444,7 @@ L.Control.JSDialogBuilder = L.Control.extend({ // before close the wizard then execute the action if (data.executionType === 'action') { builder.map.menubar._executeAction(undefined, data.id); - } else if (!builder.map._clip.filterExecCopyPaste(data.command)) { + } else if (!builder.map._clip || !builder.map._clip.filterExecCopyPaste(data.command)) { builder.map.sendUnoCommand(data.command) } }); diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js index 58d9cf849..778013556 100644 --- a/loleaflet/src/map/Map.js +++ b/loleaflet/src/map/Map.js @@ -58,7 +58,7 @@ L.Map = L.Evented.extend({ this.options.documentContainer = L.DomUtil.get(this.options.documentContainer); } - if (!window.ThisIsTheiOSApp) + if (!window.ThisIsTheiOSApp && !window.ThisIsTheAndroidApp) this._clip = L.clipboard(this); this._initContainer(id); this._initLayout(); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits