diff options
-rw-r--r-- | android/Bootstrap/src/org/libreoffice/android/LibreOfficeKit.java | 135 | ||||
-rw-r--r-- | include/osl/detail/android-bootstrap.h | 7 | ||||
-rw-r--r-- | sal/Library_lo-bootstrap.mk | 1 | ||||
-rw-r--r-- | sal/android/libreofficekit-jni.c | 130 | ||||
-rw-r--r-- | sal/android/lo-bootstrap.c | 11 |
5 files changed, 277 insertions, 7 deletions
diff --git a/android/Bootstrap/src/org/libreoffice/android/LibreOfficeKit.java b/android/Bootstrap/src/org/libreoffice/android/LibreOfficeKit.java new file mode 100644 index 000000000000..82b889e2548f --- /dev/null +++ b/android/Bootstrap/src/org/libreoffice/android/LibreOfficeKit.java @@ -0,0 +1,135 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + */ + +package org.libreoffice.android; + +import android.app.Activity; +import android.content.pm.ApplicationInfo; +import android.util.Log; + +import java.io.File; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; + +// final because subclassing would be meaningless. +public final class LibreOfficeKit +{ + // private constructor because instantiating would be meaningless + private LibreOfficeKit() + { + } + + private static String TAG = "lo-bootstrap"; + + // Native methods in this class are all implemented in + // sal/android/lo-bootstrap.c as the lo-bootstrap library is loaded with + // System.loadLibrary() and Android's JNI works only to such libraries, it + // seems. + + private static native boolean init(String dataDir, + String cacheDir, + String apkFile); + + // Extracts files in the .apk that need to be extraced into the app's tree + static native void extract_files(); + +/* + // Wrapper for getpid() + public static native int getpid(); + + // Wrapper for system() + public static native void system(String cmdline); +*/ + // Wrapper for putenv() + public static native void putenv(String string); +/* + // A wrapper for InitVCL() in libvcl (svmain.cxx), called indirectly + // through the lo-bootstrap library + public static native void initVCL(); + + // A wrapper for osl_setCommandArgs(). Before calling + // osl_setCommandArgs(), argv[0] is prefixed with the parent directory of + // where the lo-bootstrap library is. + public static native void setCommandArgs(String[] argv); +*/ + // A method that starts a thread to redirect stdout and stderr writes to + // the Android logging mechanism, or stops the redirection. + public static native boolean redirect_stdio(boolean state); +/* + // The DIB returned by css.awt.XBitmap.getDIB is in BGR_888 form, at least + // for Writer documents. We need it in Android's Bitmap.Config.ARGB_888 + // format, which actually is RGBA_888, whee... At least in Android 4.0.3, + // at least on my device. No idea if it is always like that or not, the + // documentation sucks. + public static native void twiddle_BGR_to_RGBA(byte[] source, int offset, int width, int height, ByteBuffer destination); + + public static native void force_full_alpha_array(byte[] array, int offset, int length); + + public static native void force_full_alpha_bb(ByteBuffer buffer, int offset, int length); + + public static native long new_byte_buffer_wrapper(ByteBuffer bbuffer); + + public static native void delete_byte_buffer_wrapper(long bbw); +*/ + + static boolean init_done = false; + + // This init() method should be called from the upper Java level of + // LO-based apps. + public static synchronized void init(Activity activity) + { + if (init_done) + return; + + String dataDir = null; + + ApplicationInfo ai = activity.getApplicationInfo(); + dataDir = ai.dataDir; + Log.i(TAG, String.format("dataDir=%s\n", dataDir)); + + redirect_stdio(true); + + if (!init(dataDir, + activity.getApplication().getCacheDir().getAbsolutePath(), + activity.getApplication().getPackageResourcePath())) + return; + + // Extract files from the .apk that can't be used mmapped directly from it + extract_files(); + + // If we notice that a fonts.conf file was extracted, automatically + // set the FONTCONFIG_FILE env var. + InputStream i; + try { + i = activity.getAssets().open("unpack/etc/fonts/fonts.conf"); + } + catch (java.io.IOException e) { + i = null; + } + putenv("OOO_DISABLE_RECOVERY=1"); + if (i != null) + putenv("FONTCONFIG_FILE=" + dataDir + "/etc/fonts/fonts.conf"); + + // TMPDIR is used by osl_getTempDirURL() + putenv("TMPDIR=" + activity.getCacheDir().getAbsolutePath()); + + init_done = true; + } + + // Now with static loading we always have all native code in one native + // library which we always call liblo-native-code.so, regardless of the + // app. The library has already been unpacked into /data/data/<app + // name>/lib at installation time by the package manager. + static { + System.loadLibrary("lo-native-code"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/osl/detail/android-bootstrap.h b/include/osl/detail/android-bootstrap.h index 002027a5d8a0..b18531bb65e2 100644 --- a/include/osl/detail/android-bootstrap.h +++ b/include/osl/detail/android-bootstrap.h @@ -38,6 +38,13 @@ JavaVM *lo_get_javavm(void); const char *lo_get_app_data_dir(void); +#define UNPACK_TREE "/assets/unpack" +#define UNPACK_TREE_GZ "/assets/gz.unpack" + +int setup_cdir(void); +int setup_assets_tree(void); +void extract_files(const char *root, const char *prefix, int gzipped); + #ifdef __cplusplus } #endif diff --git a/sal/Library_lo-bootstrap.mk b/sal/Library_lo-bootstrap.mk index 14380915162f..3dc4bf9dfeaa 100644 --- a/sal/Library_lo-bootstrap.mk +++ b/sal/Library_lo-bootstrap.mk @@ -19,6 +19,7 @@ $(eval $(call gb_Library_add_libs,lo-bootstrap,\ )) $(eval $(call gb_Library_add_cobjects,lo-bootstrap,\ + sal/android/libreofficekit-jni \ sal/android/lo-bootstrap \ )) diff --git a/sal/android/libreofficekit-jni.c b/sal/android/libreofficekit-jni.c new file mode 100644 index 000000000000..3563d5b7891e --- /dev/null +++ b/sal/android/libreofficekit-jni.c @@ -0,0 +1,130 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <time.h> + +#include <jni.h> + +#include <android/log.h> + +#include <osl/detail/android-bootstrap.h> + +//#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "LibreOfficeKit", __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "LibreOfficeKit", __VA_ARGS__)) + +/* These are valid / used in all apps. */ +extern const char *data_dir; +extern const char *cache_dir; +extern void *apk_file; +extern int apk_file_size; + +extern void Java_org_libreoffice_android_Bootstrap_putenv(JNIEnv* env, jobject clazz, jstring string); +extern jboolean Java_org_libreoffice_android_Bootstrap_redirect_1stdio(JNIEnv* env, jobject clazz, jboolean state); +extern void Java_org_libreoffice_android_Bootstrap_extract_1files(JNIEnv* env, jobject clazz); + +/// Call the same method from Bootstrap. +__attribute__ ((visibility("default"))) +void +Java_org_libreoffice_android_LibreOfficeKit_putenv(JNIEnv* env, + jobject clazz, + jstring string) +{ + Java_org_libreoffice_android_Bootstrap_putenv(env, clazz, string); +} + +/// Call the same method from Bootstrap. +__attribute__ ((visibility("default"))) +jboolean +Java_org_libreoffice_android_LibreOfficeKit_redirect_1stdio(JNIEnv* env, + jobject clazz, + jboolean state) +{ + return Java_org_libreoffice_android_Bootstrap_redirect_1stdio(env, clazz, state); +} + +/// Call the same method from Bootstrap. +__attribute__ ((visibility("default"))) +void +Java_org_libreoffice_android_LibreOfficeKit_extract_1files(JNIEnv* env, + jobject clazz) +{ + Java_org_libreoffice_android_Bootstrap_extract_1files(env, clazz); +} + +/// Initialize the LibreOfficeKit. +__attribute__ ((visibility("default"))) +jboolean +Java_org_libreoffice_android_LibreOfficeKit_init__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2 + (JNIEnv* env, + jobject clazz, + jstring dataDir, + jstring cacheDir, + jstring apkFile) +{ + struct stat st; + int fd; + const char *dataDirPath; + const char *cacheDirPath; + const char *apkFilePath; + + (void) clazz; + + dataDirPath = (*env)->GetStringUTFChars(env, dataDir, NULL); + data_dir = strdup(dataDirPath); + (*env)->ReleaseStringUTFChars(env, dataDir, dataDirPath); + + cacheDirPath = (*env)->GetStringUTFChars(env, cacheDir, NULL); + cache_dir = strdup(cacheDirPath); + (*env)->ReleaseStringUTFChars(env, cacheDir, cacheDirPath); + + apkFilePath = (*env)->GetStringUTFChars(env, apkFile, NULL); + + fd = open(apkFilePath, O_RDONLY); + if (fd == -1) { + LOGE("Could not open %s", apkFilePath); + (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath); + return JNI_FALSE; + } + if (fstat(fd, &st) == -1) { + LOGE("Could not fstat %s", apkFilePath); + close(fd); + (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath); + return JNI_FALSE; + } + apk_file = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + if (apk_file == MAP_FAILED) { + LOGE("Could not mmap %s", apkFilePath); + (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath); + return JNI_FALSE; + } + apk_file_size = st.st_size; + + (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath); + + if (!setup_cdir()) + return JNI_FALSE; + + if (!setup_assets_tree()) + return JNI_FALSE; + + return JNI_TRUE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/android/lo-bootstrap.c b/sal/android/lo-bootstrap.c index 49f9b3aa627c..973c1b25116a 100644 --- a/sal/android/lo-bootstrap.c +++ b/sal/android/lo-bootstrap.c @@ -28,7 +28,7 @@ #include "uthash.h" -#include "osl/detail/android-bootstrap.h" +#include <osl/detail/android-bootstrap.h> #undef LOGI @@ -142,7 +142,7 @@ cdir_entry_size(struct cdir_entry *entry) letoh16(entry->file_comment_size); } -static int +int setup_cdir(void) { struct cdir_end *dirend = (struct cdir_end *)((char *) apk_file + apk_file_size - sizeof(*dirend)); @@ -221,7 +221,7 @@ handle_one_asset(struct cdir_entry *entry) } } -static int +int setup_assets_tree(void) { int count = cdir_entries; @@ -629,9 +629,6 @@ lo_apk_lstat(const char *path, return -1; } -#define UNPACK_TREE "/assets/unpack" -#define UNPACK_TREE_GZ "/assets/gz.unpack" - static int mkdir_p(const char *dirname) { @@ -718,7 +715,7 @@ extract_gzipped(const char *filename, return total; } -static void +void extract_files(const char *root, const char *prefix, int gzipped) |