[Libreoffice-commits] online.git: 2 commits - android/app .gitignore loleaflet/Makefile.am wsd/LOOLWSD.cpp
Libreoffice Gerrit user
logerrit at kemper.freedesktop.org
Wed Feb 13 14:19:01 UTC 2019
.gitignore | 1
android/app/src/main/cpp/CMakeLists.txt.in | 2
android/app/src/main/cpp/androidapp.c | 14
android/app/src/main/cpp/androidapp.cpp | 274 ++++++++++
android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java | 12
loleaflet/Makefile.am | 7
wsd/LOOLWSD.cpp | 2
7 files changed, 293 insertions(+), 19 deletions(-)
New commits:
commit dc37e633efd7bf61072f7c3804d23928249f97e2
Author: Jan Holesovsky <kendy at collabora.com>
AuthorDate: Wed Feb 13 15:09:37 2019 +0100
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Wed Feb 13 15:17:50 2019 +0100
android: JNI for the LOOLWSD initialization.
For the moment it crashes, so the actual call is commented out.
Change-Id: Ie4acb2a91f280dcc08951dcce417b8d4552cbfe7
diff --git a/android/app/src/main/cpp/CMakeLists.txt.in b/android/app/src/main/cpp/CMakeLists.txt.in
index c6b293da9..8a1c4a925 100644
--- a/android/app/src/main/cpp/CMakeLists.txt.in
+++ b/android/app/src/main/cpp/CMakeLists.txt.in
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.4.1)
add_library(androidapp SHARED
- androidapp.c
+ androidapp.cpp
../../../../../common/FileUtil.cpp
../../../../../common/Log.cpp
../../../../../common/MessageQueue.cpp
diff --git a/android/app/src/main/cpp/androidapp.c b/android/app/src/main/cpp/androidapp.c
deleted file mode 100644
index 532a9e59b..000000000
--- a/android/app/src/main/cpp/androidapp.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-#include "androidapp.h"
-
-int loolwsd_server_socket_fd = -1;
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/android/app/src/main/cpp/androidapp.cpp b/android/app/src/main/cpp/androidapp.cpp
new file mode 100644
index 000000000..25dfc63c7
--- /dev/null
+++ b/android/app/src/main/cpp/androidapp.cpp
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <config.h>
+#include <jni.h>
+#include <android/log.h>
+
+#include <thread>
+
+#include <FakeSocket.hpp>
+#include <Log.hpp>
+#include <LOOLWSD.hpp>
+#include <Protocol.hpp>
+#include <Util.hpp>
+
+const int SHOW_JS_MAXLEN = 70;
+
+int loolwsd_server_socket_fd = -1;
+
+static std::string fileURL;
+static LOOLWSD *loolwsd = nullptr;
+static int fakeClientFd;
+static int closeNotificationPipeForForwardingThread[2];
+
+#if 0
+static void send2JS_ready_callback(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ free(user_data);
+}
+
+static void send2JS(const std::vector<char>& buffer)
+{
+ LOG_TRC_NOFILE("Send to JS: " << LOOLProtocol::getAbbreviatedMessage(buffer.data(), buffer.size()));
+
+ std::string js;
+
+ // Check if the message is binary. We say that any message that isn't just a single line is
+ // "binary" even if that strictly speaking isn't the case; for instance the commandvalues:
+ // message has a long bunch of non-binary JSON on multiple lines. But _onMessage() in Socket.js
+ // handles it fine even if such a message, too, comes in as an ArrayBuffer. (Look for the
+ // "textMsg = String.fromCharCode.apply(null, imgBytes);".)
+
+ const char *newline = (const char *)memchr(buffer.data(), '\n', buffer.size());
+ if (newline != nullptr)
+ {
+ // The data needs to be an ArrayBuffer
+ js = "window.TheFakeWebSocket.onmessage({'data': Base64ToArrayBuffer('";
+ gchar *base64 = g_base64_encode((const guchar*)buffer.data(), buffer.size());
+ js = js + std::string(base64);
+ g_free(base64);
+ js = js + "')});";
+ }
+ else
+ {
+ const unsigned char *ubufp = (const unsigned char *)buffer.data();
+ std::vector<char> data;
+ for (int i = 0; i < buffer.size(); i++)
+ {
+ if (ubufp[i] < ' ' || ubufp[i] == '\'' || ubufp[i] == '\\')
+ {
+ data.push_back('\\');
+ data.push_back('x');
+ data.push_back("0123456789abcdef"[(ubufp[i] >> 4) & 0x0F]);
+ data.push_back("0123456789abcdef"[ubufp[i] & 0x0F]);
+ }
+ else
+ {
+ data.push_back(ubufp[i]);
+ }
+ }
+ data.push_back(0);
+
+ js = "window.TheFakeWebSocket.onmessage({'data': '";
+ js = js + std::string(buffer.data(), buffer.size());
+ js = js + "'});";
+ }
+
+ std::string subjs = js.substr(0, std::min(std::string::size_type(SHOW_JS_MAXLEN), js.length()));
+ if (js.length() > SHOW_JS_MAXLEN)
+ subjs += "...";
+
+ LOG_TRC_NOFILE( "Evaluating JavaScript: " << subjs);
+
+ char *jscopy = strdup(js.c_str());
+ g_idle_add([](gpointer data)
+ {
+ char *jscopy = (char*) data;
+ webkit_web_view_run_javascript(webView, jscopy, nullptr, send2JS_ready_callback, jscopy);
+ return FALSE;
+ }, jscopy);
+}
+
+static char *js_result_as_gstring(WebKitJavascriptResult *js_result)
+{
+#if WEBKIT_CHECK_VERSION(2,22,0) // unclear when this API changed ...
+ JSCValue *value = webkit_javascript_result_get_js_value(js_result);
+ if (jsc_value_is_string(value))
+ return jsc_value_to_string(value);
+ else
+ return nullptr;
+#else // older Webkits
+ JSValueRef value = webkit_javascript_result_get_value(js_result);
+ JSContextRef ctx = webkit_javascript_result_get_global_context(js_result);
+ if (JSValueIsString(ctx, value))
+ {
+ const JSStringRef js_str = JSValueToStringCopy(ctx, value, nullptr);
+ size_t gstring_max = JSStringGetMaximumUTF8CStringSize(js_str);
+ char *gstring = (char *)g_malloc(gstring_max);
+ if (gstring)
+ JSStringGetUTF8CString(js_str, gstring, gstring_max);
+ else
+ LOG_TRC_NOFILE("No string");
+ JSStringRelease(js_str);
+ return gstring;
+ }
+ else
+ LOG_TRC_NOFILE("Unexpected object type " << JSValueGetType(ctx, value));
+ return nullptr;
+#endif
+}
+
+// TODO handle the message from JS here
+static void handle_lool_message(WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
+{
+ gchar *string_value = js_result_as_gstring(js_result);
+
+ if (string_value)
+ {
+ LOG_TRC_NOFILE("From JS: lool: " << string_value);
+
+ if (strcmp(string_value, "HULLO") == 0)
+ {
+ // Now we know that the JS has started completely
+
+ // Contact the permanently (during app lifetime) listening LOOLWSD server
+ // "public" socket
+ assert(loolwsd_server_socket_fd != -1);
+ int rc = fakeSocketConnect(fakeClientFd, loolwsd_server_socket_fd);
+ assert(rc != -1);
+
+ // Create a socket pair to notify the below thread when the document has been closed
+ fakeSocketPipe2(closeNotificationPipeForForwardingThread);
+
+ // Start another thread to read responses and forward them to the JavaScript
+ std::thread([]
+ {
+ Util::setThreadName("app2js");
+ while (true)
+ {
+ struct pollfd pollfd[2];
+ pollfd[0].fd = fakeClientFd;
+ pollfd[0].events = POLLIN;
+ pollfd[1].fd = closeNotificationPipeForForwardingThread[1];
+ pollfd[1].events = POLLIN;
+ if (fakeSocketPoll(pollfd, 2, -1) > 0)
+ {
+ if (pollfd[1].revents == POLLIN)
+ {
+ // The code below handling the "BYE" fake Websocket
+ // message has closed the other end of the
+ // closeNotificationPipeForForwardingThread. Let's close
+ // the other end too just for cleanliness, even if a
+ // FakeSocket as such is not a system resource so nothing
+ // is saved by closing it.
+ fakeSocketClose(closeNotificationPipeForForwardingThread[1]);
+
+ // Close our end of the fake socket connection to the
+ // ClientSession thread, so that it terminates
+ fakeSocketClose(fakeClientFd);
+
+ return;
+ }
+ if (pollfd[0].revents == POLLIN)
+ {
+ int n = fakeSocketAvailableDataLength(fakeClientFd);
+ if (n == 0)
+ return;
+ std::vector<char> buf(n);
+ n = fakeSocketRead(fakeClientFd, buf.data(), n);
+ send2JS(buf);
+ }
+ }
+ else
+ break;
+ }
+ assert(false);
+ }).detach();
+
+ // First we simply send it the URL. This corresponds to the GET request with Upgrade to
+ // WebSocket.
+ LOG_TRC_NOFILE("Actually sending to Online:" << fileURL);
+
+ // Must do this in a thread, too, so that we can return to the GTK+ main loop
+ std::thread([]
+ {
+ struct pollfd pollfd;
+ pollfd.fd = fakeClientFd;
+ pollfd.events = POLLOUT;
+ fakeSocketPoll(&pollfd, 1, -1);
+ fakeSocketWrite(fakeClientFd, fileURL.c_str(), fileURL.size());
+ }).detach();
+ }
+ else if (strcmp(string_value, "BYE") == 0)
+ {
+ LOG_TRC_NOFILE("Document window terminating on JavaScript side. Closing our end of the socket.");
+
+ // Close one end of the socket pair, that will wake up the forwarding thread above
+ fakeSocketClose(closeNotificationPipeForForwardingThread[0]);
+
+ // ???
+ }
+ else
+ {
+ // As above
+ char *string_copy = strdup(string_value);
+ std::thread([=]
+ {
+ struct pollfd pollfd;
+ pollfd.fd = fakeClientFd;
+ pollfd.events = POLLOUT;
+ fakeSocketPoll(&pollfd, 1, -1);
+ fakeSocketWrite(fakeClientFd, string_copy, strlen(string_copy));
+ free(string_copy);
+ }).detach();
+ }
+ g_free(string_value);
+ }
+ else
+ LOG_TRC_NOFILE("From JS: lool: some object");
+}
+#endif
+
+/// Create the LOOLWSD instance.
+extern "C" JNIEXPORT void JNICALL
+Java_org_libreoffice_androidapp_MainActivity_createLOOLWSD(JNIEnv*, jobject)
+{
+ Log::initialize("Mobile", "trace", false, false, {});
+ Util::setThreadName("main");
+
+ fakeSocketSetLoggingCallback([](const std::string& line)
+ {
+ LOG_TRC_NOFILE(line);
+ });
+
+ std::thread([]
+ {
+ assert(loolwsd == nullptr);
+ char *argv[2];
+ argv[0] = strdup("mobile");
+ argv[1] = nullptr;
+ Util::setThreadName("app");
+ while (true)
+ {
+ loolwsd = new LOOLWSD();
+ loolwsd->run(1, argv);
+ delete loolwsd;
+ LOG_TRC("One run of LOOLWSD completed");
+ }
+ }).detach();
+
+ fakeClientFd = fakeSocketSocket();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/android/app/src/main/cpp/androidapp.h b/android/app/src/main/cpp/androidapp.hpp
similarity index 100%
rename from android/app/src/main/cpp/androidapp.h
rename to android/app/src/main/cpp/androidapp.hpp
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java b/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java
index 9388372b4..5a692cb62 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java
+++ b/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java
@@ -25,6 +25,8 @@ public class MainActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ //createLOOLWSD();
+
final WebView browser = findViewById(R.id.browser);
browser.setWebViewClient(new WebViewClient());
@@ -32,7 +34,10 @@ public class MainActivity extends AppCompatActivity {
browserSettings.setJavaScriptEnabled(true);
browser.addJavascriptInterface(new JavaScriptInterface(), "MainHandler");
- browser.loadUrl("file:///android_asset/dist/loleaflet.html");
+ browser.loadUrl("file:///android_asset/dist/loleaflet.html?file_path=" +
+ "file:///android_asset/dist/hello-world.odt" + // TODO the real URL here
+ "&closebutton=1&permission=edit" +
+ "&debug=true"); // TODO remove later?
Button jsButton = findViewById(R.id.js_button);
jsButton.setOnClickListener(new View.OnClickListener() {
@@ -43,6 +48,11 @@ public class MainActivity extends AppCompatActivity {
}
);
}
+
+ static {
+ System.loadLibrary("androidapp");
+ }
+ public native void createLOOLWSD();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 5dfec75a7..1f7ab0556 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -141,7 +141,7 @@ using Poco::Net::PartHandler;
#elif GTKAPP
#include "gtk.hpp"
#elif defined(__ANDROID__)
-#include "androidapp.h"
+#include "androidapp.hpp"
#endif
#endif
commit b7513394bd6ab87be91a306b4e081a446e90a4bc
Author: Jan Holesovsky <kendy at collabora.com>
AuthorDate: Wed Feb 13 14:56:05 2019 +0100
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Wed Feb 13 14:56:05 2019 +0100
android: Copy the test documents to the assets too.
Change-Id: Iaaf8d70b84adf7945461a50c4771dc984ffa08ff
diff --git a/.gitignore b/.gitignore
index aa2c717fb..6f4dddc9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -93,6 +93,7 @@ ios/Mobile/Assets.xcassets/AppIcon.appiconset
# android stuff
/android/app/src/main/assets/dist
+/android/app/src/main/assets/hello-world.od*
/android/app/src/main/cpp/CMakeLists.txt
# backup and temporary editor files: the only convenience rules allowed here.
diff --git a/loleaflet/Makefile.am b/loleaflet/Makefile.am
index dcdcf31fc..d5b54001a 100644
--- a/loleaflet/Makefile.am
+++ b/loleaflet/Makefile.am
@@ -164,8 +164,11 @@ build-loleaflet: | $(LOLEAFLET_L10N_DST) \
$(builddir)/dist/loleaflet.html
@echo "build loleaflet completed"
if ENABLE_ANDROIDAPP
- @rm -rf $(srcdir)/../android/app/src/main/assets/dist
- @cp -a $(builddir)/dist $(srcdir)/../android/app/src/main/assets/
+ @rm -rf $(abs_top_srcdir)/android/app/src/main/assets/dist
+ @cp -a $(builddir)/dist $(abs_top_srcdir)/android/app/src/main/assets/
+ @cp -a $(abs_top_srcdir)/test/data/hello.odt $(abs_top_srcdir)/android/app/src/main/assets/hello-world.odt
+ @cp -a $(abs_top_srcdir)/test/data/hello.ods $(abs_top_srcdir)/android/app/src/main/assets/hello-world.ods
+ @cp -a $(abs_top_srcdir)/test/data/hello.odp $(abs_top_srcdir)/android/app/src/main/assets/hello-world.odp
@echo
@echo "Copied JS, HTML and CSS to the Android project (android/app/src/main/assets/dist)."
@echo
More information about the Libreoffice-commits
mailing list