[Libreoffice-commits] core.git: Branch 'feature/android-viewer' - 1280 commits - accessibility/inc accessibility/source android/CustomTarget_lo_android.mk android/experimental android/Module_android.mk avmedia/Library_avmedia.mk avmedia/Library_avmediaogl.mk avmedia/source basctl/source basctl/uiconfig basegfx/source basic/CppunitTest_basic_coverage.mk basic/CppunitTest_basic_enable.mk basic/CppunitTest_basic_nested_struct.mk basic/CppunitTest_basic_scanner.mk basic/CppunitTest_basic_vba.mk basic/qa basic/source binaryurp/source bin/distro-install-desktop-integration bin/distro-install-file-lists bin/update_pch.sh bridges/inc bridges/Library_cpp_uno.mk bridges/source bridges/test canvas/source chart2/CppunitTest_chart2_export.mk chart2/CppunitTest_chart2_import.mk chart2/CppunitTest_chart2_xshape.mk chart2/inc chart2/Library_chartcontroller.mk chart2/Library_chartcore.mk chart2/opengl chart2/Package_opengl.mk chart2/qa chart2/source chart2/uiconfig chart2/UIConfig_chart2.mk cli_ure/CustomTarget_c li_ure_assemblies.mk cli_ure/Library_cli_cppuhelper_native.mk cli_ure/source codemaker/source comphelper/source compilerplugins/clang config.guess config_host/config_features.h.in config_host.mk.in configmgr/source config.sub configure.ac connectivity/CppunitTest_connectivity_ado.mk connectivity/CppunitTest_connectivity_commontools.mk connectivity/CppunitTest_connectivity_mork.mk connectivity/inc connectivity/Library_ado.mk connectivity/Library_calc.mk connectivity/Library_dbase.mk connectivity/Library_dbpool2.mk connectivity/Library_firebird_sdbc.mk connectivity/Library_mysql.mk connectivity/Library_odbc.mk connectivity/Library_postgresql-sdbc-impl.mk connectivity/qa connectivity/source connectivity/workben cppcanvas/CppunitTest_cppcanvas_emfplus.mk cppcanvas/CppunitTest_cppcanvas_test.mk cppcanvas/inc cppcanvas/Library_cppcanvas.mk cppcanvas/source cppuhelper/inc cppuhelper/Library_cppuhelper.mk cppuhelper/qa cppuhelper/source cppuhelper/test cppu/source cui/AllLangResTarget_cui.m k cui/source cui/uiconfig cui/UIConfig_cui.mk dbaccess/CppunitTest_dbaccess_dialog_save.mk dbaccess/CppunitTest_dbaccess_embeddeddb_performancetest.mk dbaccess/CppunitTest_dbaccess_firebird_test.mk dbaccess/CppunitTest_dbaccess_hsqldb_test.mk dbaccess/CppunitTest_dbaccess_macros_test.mk dbaccess/inc dbaccess/Library_dbaxml.mk dbaccess/Library_dbmm.mk dbaccess/Library_sdbt.mk dbaccess/source dbaccess/uiconfig dbaccess/UIConfig_dbaccess.mk desktop/inc desktop/Library_deploymentgui.mk desktop/Library_deploymentmisc.mk desktop/Library_deployment.mk desktop/Library_libreoffice.mk desktop/Library_sofficeapp.mk desktop/Module_desktop.mk desktop/qa desktop/source desktop/test desktop/uiconfig desktop/UIConfig_deployment.mk desktop/unx desktop/win32 dictionaries download.lst drawinglayer/source editeng/CppunitTest_editeng_core.mk editeng/source embeddedobj/source extensions/AllLangResTarget_bib.mk extensions/AllLangResTarget_scn.mk extensions/CppunitTest_extensions_test_update.mk extensions/ inc extensions/Library_npsoplugin.mk extensions/Module_extensions.mk extensions/source extensions/test extensions/uiconfig extensions/UIConfig_sbibliography.mk extensions/UIConfig_scanner.mk extensions/WinResTarget_activex.mk external/coinmp external/collada2gltf external/curl external/icu external/libabw external/libfreehand external/libgltf external/libmwaw external/libodfgen external/librevenge external/libvisio external/libwps external/lpsolve external/nss external/openssl external/python3 external/rhino external/unixODBC extras/CustomTarget_autocorr.mk extras/CustomTarget_autotextuser.mk extras/Module_extras.mk extras/Package_autocorr.mk extras/Package_autotextuser.mk extras/source filter/Configuration_filter.mk filter/CppunitTest_filter_pcx_test.mk filter/CppunitTest_filter_pict_test.mk filter/CppunitTest_filter_ppm_test.mk filter/CppunitTest_filter_psd_test.mk filter/CppunitTest_filter_ras_test.mk filter/CppunitTest_filter_tga_test.mk filter/CppunitTest_filter_tiff_test.mk fi lter/CppunitTest_filter_xslt.mk filter/Library_filterconfig.mk filter/qa filter/source filter/uiconfig forms/source formula/inc formula/Module_formula.mk formula/source formula/uiconfig formula/UIConfig_formula.mk fpicker/source fpicker/uiconfig framework/inc framework/Library_fwe.mk framework/Library_fwi.mk framework/Library_fwl.mk framework/source helpcompiler/inc helpcompiler/source helpcontent2 hwpfilter/CppunitTest_hwpfilter_test_hwpfilter.mk hwpfilter/inc hwpfilter/Library_hwp.mk hwpfilter/source i18nlangtag/qa i18nlangtag/source i18npool/source idlc/inc idlc/source idl/source include/avmedia include/basebmp include/basegfx include/basic include/canvas include/codemaker include/com include/comphelper include/connectivity include/cppu include/cppuhelper include/cppunittester include/dbaccess include/editeng include/filter include/formula include/framework include/helpcompiler include/i18nlangtag include/jvmaccess include/LibreOfficeKit include/o3tl include/oox include/osl inclu de/package include/rtl include/sal include/salhelper include/sfx2 include/sot include/store include/svl include/svtools include/svx include/systools include/test include/toolkit include/tools include/typelib include/ucbhelper include/uno include/unotest include/unotools include/vbahelper include/vcl include/writerperfect include/xmloff include/xmlreader include/xmlscript instsetoo_native/inc_openoffice ios/experimental io/source jurt/source jvmaccess/source jvmfwk/plugins jvmfwk/source l10ntools/inc l10ntools/source libreofficekit/Executable_gtktiledviewer.mk libreofficekit/Library_libreofficekitgtk.mk libreofficekit/Makefile libreofficekit/Module_libreofficekit.mk libreofficekit/qa libreofficekit/source libreofficekit/StaticLibrary_libreofficekit.mk lingucomponent/source linguistic/source lotuswordpro/CppunitTest_lotuswordpro_test_lotuswordpro.mk lotuswordpro/Library_lwpft.mk lotuswordpro/source Makefile.in odk/CustomTarget_check.mk odk/CustomTarget_javadoc.mk odk/examples odk/Pack age_examples.mk odk/source offapi/com offapi/UnoApi_offapi.mk officecfg/CustomTarget_registry.mk officecfg/registry oovbaapi/ooo oox/inc oox/source package/inc package/Library_package2.mk package/Library_xstor.mk package/source postprocess/CppunitTest_services.mk postprocess/CustomTarget_registry.mk postprocess/qa pyuno/qa pyuno/source qadevOOo/runner qadevOOo/tests readlicense_oo/docs readlicense_oo/license registry/source reportdesign/inc reportdesign/source RepositoryExternal.mk Repository.mk RepositoryModule_host.mk rsc/inc rsc/source sal/cpprt sal/cppunittester salhelper/source salhelper/test sal/osl sal/qa sal/rtl sax/CppunitTest_sax_parser.mk sax/source scaddins/source sc/AllLangResTarget_sc.mk sccomp/CppunitTest_sccomp_lpsolver.mk sccomp/source sc/CppunitTest_sc_annotationobj.mk sc/CppunitTest_sc_annotationsobj.mk sc/CppunitTest_sc_cellrangeobj.mk sc/CppunitTest_sc_databaserangeobj.mk sc/CppunitTest_sc_datapilotfieldobj.mk sc/CppunitTest_sc_datapilottableobj.mk sc/CppunitTes t_sc_editfieldobj_cell.mk sc/CppunitTest_sc_editfieldobj_header.mk sc/CppunitTest_sc_filters_test.mk sc/CppunitTest_sc_html_export_test.mk sc/CppunitTest_sc_macros_test.mk sc/CppunitTest_sc_modelobj.mk sc/CppunitTest_sc_namedrangeobj.mk sc/CppunitTest_sc_namedrangesobj.mk sc/CppunitTest_sc_opencl_test.mk sc/CppunitTest_sc_outlineobj.mk sc/CppunitTest_sc_rangelst_test.mk sc/CppunitTest_sc_subsequent_export_test.mk sc/CppunitTest_sc_subsequent_filters_test.mk sc/CppunitTest_sc_tablesheetobj.mk sc/CppunitTest_sc_tablesheetsobj.mk sc/CppunitTest_sc_ucalc.mk sc/inc scp2/AutoInstall.mk scp2/InstallModule_ooo.mk scp2/InstallModule_ure.mk scp2/source sc/qa scripting/source scripting/workben sc/source sc/uiconfig sc/UIConfig_scalc.mk sc/workben sd/AllLangResTarget_sd.mk sd/CppunitTest_sd_filters_test.mk sd/CppunitTest_sd_html_export_tests.mk sd/CppunitTest_sd_import_tests.mk sdext/CppunitTest_sdext_pdfimport.mk sdext/inc sdext/Library_PresentationMinimizer.mk sdext/Library_PresenterScreen.mk sdext/source sd/inc sd/Library_sd.mk sd/qa sd/sdi sd/source sd/uiconfig sd/UIConfig_simpress.mk sd/workben setup_native/source sfx2/qa sfx2/source sfx2/uiconfig shell/inc shell/Module_shell.mk shell/source slideshow/source smoketest/Executable_libtest.mk smoketest/libtest.cxx solenv/bin solenv/gbuild soltools/cpp soltools/mkdepend sot/inc sot/Library_sot.mk sot/source starmath/CppunitTest_starmath_qa_cppunit.mk starmath/inc starmath/source starmath/uiconfig stoc/inc stoc/source stoc/test store/source store/workben svgio/CppunitTest_svgio.mk svgio/inc svgio/Library_svgio.mk svgio/source svl/CppunitTest_svl_itempool.mk svl/CppunitTest_svl_items.mk svl/CppunitTest_svl_qa_cppunit.mk svl/Module_svl.mk svl/qa svl/source svtools/source svtools/uiconfig svx/inc svx/Library_svx.mk svx/Module_svx.mk svx/source svx/uiconfig svx/UIConfig_svx.mk sw/AllLangResTarget_sw.mk sw/CppunitTest_sw_filters_test.mk sw/CppunitTest_sw_htmlexport.mk sw/CppunitTest_sw_macros_test.mk sw/CppunitTest_sw_odfexpor t.mk sw/CppunitTest_sw_odfimport.mk sw/CppunitTest_sw_ooxmlexport.mk sw/CppunitTest_sw_ooxmlimport.mk sw/CppunitTest_sw_ooxmlsdrexport.mk sw/CppunitTest_sw_ooxmlw14export.mk sw/CppunitTest_sw_rtfexport.mk sw/CppunitTest_sw_rtfimport.mk sw/CppunitTest_sw_tox.mk sw/CppunitTest_sw_uiwriter.mk sw/CppunitTest_sw_uwriter.mk sw/CppunitTest_sw_ww8export.mk sw/CppunitTest_sw_ww8import.mk sw/inc sw/Library_sw.mk sw/Module_sw.mk sw/qa sw/sdi sw/source sw/uiconfig sw/UIConfig_swriter.mk sysui/desktop test/Library_subsequenttest.mk test/Library_test.mk test/Library_vclbootstrapprotector.mk test/Module_test.mk test/source testtools/source toolkit/Library_tk.mk toolkit/source tools/Library_tl.mk tools/qa tools/source ucbhelper/source ucb/Library_ucpdav1.mk ucb/source ucb/workben udkapi/com UnoControls/inc UnoControls/source unodevtools/source unotest/source unotools/source unoxml/source unusedcode.easy ure/source uui/AllLangResTarget_uui.mk uui/inc uui/Library_uui.mk uui/source uui/uiconfig uui/UI Config_uui.mk vbahelper/inc vbahelper/Library_msforms.mk vbahelper/Library_vbahelper.mk vcl/CppunitTest_vcl_complextext.mk vcl/CppunitTest_vcl_filters_test.mk vcl/CppunitTest_vcl_wmf_test.mk vcl/CustomTarget_afm_hash.mk vcl/Executable_xid_fullscreen_on_all_monitors.mk vcl/generic vcl/headless vcl/inc vcl/Library_vcl.mk vcl/osx vcl/qa vcl/quartz vcl/source vcl/uiconfig vcl/unx vcl/win vcl/workben winaccessibility/source wizards/com writerfilter/CppunitTest_writerfilter_rtftok.mk writerfilter/CustomTarget_source.mk writerfilter/inc writerfilter/Library_writerfilter.mk writerfilter/source writerperfect/CppunitTest_writerperfect_calc.mk writerperfect/CppunitTest_writerperfect_draw.mk writerperfect/CppunitTest_writerperfect_impress.mk writerperfect/CppunitTest_writerperfect_stream.mk writerperfect/CppunitTest_writerperfect_writer.mk writerperfect/qa writerperfect/source xmerge/source xmlhelp/source xmloff/CppunitTest_xmloff_uxmloff.mk xmloff/inc xmloff/source xmlreader/source xmlscript/i nc xmlscript/Library_xmlscript.mk xmlscript/source xmlsecurity/inc xmlsecurity/Library_xmlsecurity.mk xmlsecurity/Library_xsec_fw.mk xmlsecurity/Library_xsec_xmlsec.mk xmlsecurity/source xmlsecurity/uiconfig

Tomaž Vajngerl tomaz.vajngerl at collabora.com
Thu Jun 26 02:29:08 PDT 2014


Rebased ref, commits from common ancestor:
commit b320e3a9174ebe4f274d6de5d6f232a08f612ba7
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Thu Jun 26 11:22:21 2014 +0200

    LOAndroid3: ant/make for building, Bootstrap project
    
    LOAndroid3 is based of LibreOffice4Android project which uses
    ant/make for building. By using LibreOffice4Android as the base,
    the project creates a APK archive which has all needed files
    to start LibreOffice in Android environment.
    
    Change-Id: I697d5f727bdaf93e774144ad597d7081d2609908

diff --git a/android/CustomTarget_lo_android.mk b/android/CustomTarget_lo_android.mk
new file mode 100644
index 0000000..4d32cac
--- /dev/null
+++ b/android/CustomTarget_lo_android.mk
@@ -0,0 +1,36 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+
+$(eval $(call gb_CustomTarget_CustomTarget,android/loandroid3))
+
+loandroid3_DIR := $(call gb_CustomTarget_get_workdir,android/experimental/LOAndroid3)
+
+$(call gb_CustomTarget_get_target,android/loandroid3) : \
+	$(loandroid3_DIR)/done
+
+# We want that to be built completely first,
+# so that we can serialize Ant access to Bootstrap, which is used both
+# by DocumentLoader. We don't want one Ant to be cleaning
+# out Bootstrap while another is building stuff that depends on it.
+# Yeah, this sucks
+
+$(loandroid3_DIR)/done : $(call gb_Postprocess_get_target,AllModulesButInstsetNative)
+	$(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),MAK,2)
+	cd $(SRCDIR)/android/experimental/LOAndroid3 && $(MAKE) all
+# Copy to $(BUILDDIR)/instsetoo_native as that is where the tinderbox build script
+# still looks for the .apk, and we want fresh daily builds to be uploaded. Even if
+# the apps as such are mostly useless.
+# Us "foo" instead of the old INPATH
+	mkdir -p $(BUILDDIR)/instsetoo_native/foo/bin; \
+	cp $(SRCDIR)/android/experimental/LOAndroid3/bin/*-debug.apk $(BUILDDIR)/instsetoo_native/foo/bin
+
+$(call gb_CustomTarget_get_clean_target,android/loandroid3) :
+	$(call gb_Output_announce,$(subst $(WORKDIR)/Clean/,,$@),$(false),MAK,2)
+	cd $(SRCDIR)/android/experimental/LOAndroid3 && $(MAKE) clean
+
+# vim: set noet sw=4 ts=4:
diff --git a/android/Module_android.mk b/android/Module_android.mk
index e860449..eedc57a 100644
--- a/android/Module_android.mk
+++ b/android/Module_android.mk
@@ -13,6 +13,7 @@ ifeq ($(OS),ANDROID)
 
 $(eval $(call gb_Module_add_targets,android,\
 	CustomTarget_lo4android \
+	CustomTarget_lo_android \
 	CustomTarget_android_desktop \
 ))
 
diff --git a/android/experimental/LOAndroid3/AndroidManifest.xml b/android/experimental/LOAndroid3/AndroidManifest.xml
new file mode 100644
index 0000000..81e8822
--- /dev/null
+++ b/android/experimental/LOAndroid3/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.libreoffice"
+    android:installLocation="preferExternal"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- App requires OpenGL ES 2.0 -->
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="11"/>
+
+    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/main"
+        android:label="@string/app_name"
+        android:hardwareAccelerated="true"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="LibreOfficeMainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/android/experimental/LOAndroid3/Makefile b/android/experimental/LOAndroid3/Makefile
new file mode 100644
index 0000000..4db011f
--- /dev/null
+++ b/android/experimental/LOAndroid3/Makefile
@@ -0,0 +1,128 @@
+ifeq ($(BUILDDIR),)
+include ../../../config_host.mk
+endif
+
+# The default target just builds.
+
+all: build-ant
+
+# The package of this app
+APP_PACKAGE=org.libreoffice
+
+BOOTSTRAPDIR=../../Bootstrap
+include $(BOOTSTRAPDIR)/Makefile.shared
+
+native-code.cxx: $(SRCDIR)/solenv/bin/native-code.py
+	$< -g core -g writer > $@
+
+copy-stuff:
+# Then "assets". Let the directory structure under assets mimic
+# that under solver for now.
+#
+# Please note that I have no idea what all of this is really necessary and for
+# much of this stuff being copied, no idea whether it makes any sense at all.
+# Much of this is copy-pasted from android/qa/sc/Makefile (where a couple of
+# unit tests for sc are built, and those do seem to mostly work) and
+# android/qa/desktop/Makefile (mmeeks's desktop demo, also works to some
+# extent).
+#
+	mkdir -p assets/gz.unpack/program/ure assets/lib assets/program/services assets/ure/share/misc assets/ComponentTarget/i18npool/util
+	gzip -9 <$(INSTDIR)/$(LIBO_ETC_FOLDER)/types/offapi.rdb >assets/gz.unpack/program/offapi.rdb
+	gzip -9 <$(INSTDIR)/$(LIBO_ETC_FOLDER)/types/oovbaapi.rdb >assets/gz.unpack/program/oovbaapi.rdb
+	gzip -9 <$(INSTDIR)/$(LIBO_URE_SHARE_FOLDER)/misc/types.rdb >assets/gz.unpack/program/udkapi.rdb
+# For some reason the vnd.sun.star.expand:$LO_LIB_DIR doesn't seem to work, it expands to empty!?
+	for F in program/services/services ure/share/misc/services; do \
+		sed -e 's!uri="vnd.sun.star.expand:$$LO_LIB_DIR/!uri="file://$$APP_DATA_DIR/lib/!g' <$(INSTDIR)/$$F.rdb >assets/$$F.rdb; \
+	done
+	cp $(SRC_ROOT)/odk/examples/java/DocumentHandling/test/test1.odt \
+		assets
+	cp $(WORKDIR)/ComponentTarget/i18npool/util/i18npool.component assets/ComponentTarget/i18npool/util
+#
+	mkdir -p assets/share/config
+	cp -R $(INSTDIR)/share/registry assets/share
+	cp -R $(INSTDIR)/share/config/soffice.cfg assets/share/config
+#
+# Set up rc, the "inifile". See BootstrapMap::getBaseIni(). As this app
+# doesn't use soffice_main() (at least I think it shouldn't), the
+# rtl::Bootstrap::setIniFilename() call there that hardcodes
+# /assets/program/lofficerc isn't executed. Instead the hardcoding of
+# /assets/rc in BootstrapMap::getBaseIni() gets used.
+	echo '[Bootstrap]' > assets/rc
+	echo 'Logo=1' >> assets/rc
+	echo 'NativeProgress=1' >> assets/rc
+	echo 'URE_BOOTSTRAP=file:///assets/program/fundamentalrc' >> assets/rc
+#	echo 'RTL_LOGFILE=file:///dev/log/main' >> assets/rc
+	echo 'HOME=$$APP_DATA_DIR/cache' >> assets/rc
+	echo 'OSL_SOCKET_PATH=$$APP_DATA_DIR/cache' >> assets/rc
+#
+# Set up fundamentalrc
+	echo '[Bootstrap]' > assets/program/fundamentalrc
+	echo 'LO_LIB_DIR=file://$$APP_DATA_DIR/lib/' >> assets/program/fundamentalrc
+	echo 'URE_LIB_DIR=file://$$APP_DATA_DIR/lib/' >> assets/program/fundamentalrc # checkme - is this used to find configs ?
+	echo 'BRAND_BASE_DIR=file:///assets' >> assets/program/fundamentalrc
+	echo 'CONFIGURATION_LAYERS=xcsxcu:$${BRAND_BASE_DIR}/share/registry res:$${BRAND_BASE_DIR}/share/registry' >> assets/program/fundamentalrc
+	echo 'URE_BIN_DIR=file:///assets/ure/bin/dir/nothing-here/we-can/exec-anyway' >> assets/program/fundamentalrc
+#
+# Set up unorc
+	echo '[Bootstrap]' > assets/program/unorc
+	echo 'URE_INTERNAL_LIB_DIR=file://$$APP_DATA_DIR/lib/' >> assets/program/unorc
+	echo 'UNO_TYPES=file://$$APP_DATA_DIR/program/udkapi.rdb file://$$APP_DATA_DIR/program/offapi.rdb file://$$APP_DATA_DIR/program/oovbaapi.rdb' >> assets/program/unorc
+	echo 'UNO_SERVICES=file:///assets/ure/share/misc/services.rdb file:///assets/program/services/services.rdb' >> assets/program/unorc
+#
+# Set up bootstraprc
+	echo '[Bootstrap]' > assets/program/bootstraprc
+	echo 'InstallMode=<installmode>' >> assets/program/bootstraprc
+	echo 'ProductKey=LibreOffice $(LIBO_VERSION_MAJOR).$(LIBO_VERSION_MINOR)' >> assets/program/bootstraprc
+	echo 'UserInstallation=file://$$APP_DATA_DIR' >> assets/program/bootstraprc
+#
+# Set up versionrc
+	echo '[Version]' > assets/program/versionrc
+	echo 'AllLanguages=en-US' >> assets/program/versionrc
+	echo 'BuildVersion=' >> assets/program/versionrc
+	echo 'buildid=dead-beef' >> assets/program/versionrc
+	echo 'ProductMajor=360' >> assets/program/versionrc
+	echo 'ProductMinor=1' >> assets/program/versionrc
+	echo 'ReferenceOOoMajorMinor=3.6' >> assets/program/versionrc
+#
+# .res files
+	mkdir -p assets/program/resource
+	cp $(INSTDIR)/$(LIBO_SHARE_RESOURCE_FOLDER)/*en-US.res assets/program/resource
+#
+# Assets that are unpacked at run-time into the app's data directory. These
+# are files read by non-LO code, fontconfig and freetype for now, that doesn't
+# understand "/assets" paths.
+	mkdir -p assets/unpack/etc/fonts
+	cp fonts.conf assets/unpack/etc/fonts
+# $UserInstallation/user/fonts is added to the fontconfig path in
+# vcl/generic/fontmanager/helper.cxx: psp::getFontPath(). UserInstallation is
+# set to the app's data dir above.
+	mkdir -p assets/gz.unpack/user/fonts
+	for F in $(INSTDIR)/share/fonts/truetype/Liberation*.ttf $(INSTDIR)/share/fonts/truetype/Gen*.ttf $(INSTDIR)/share/fonts/truetype/opens___.ttf; do \
+		gzip -9 <$$F >assets/gz.unpack/user/fonts/`basename $$F`; \
+	done
+#
+# Then gdbserver and gdb.setup so that we can debug with ndk-gdb.
+#
+	mkdir -p $(SODEST)
+	cp $(ANDROID_NDK_GDBSERVER) $(SODEST)
+	echo set solib-search-path ./obj/local/$(ANDROID_APP_ABI) >$(SODEST)/gdb.setup
+
+build-ant: android_version_setup copy-stuff link-so properties
+#
+# Copy jar files we need
+#
+	for F in java_uno \
+		 juh \
+		 jurt \
+		 ridl \
+		 unoloader; do \
+	    $(call COPYJAR,$(INSTDIR)/$(LIBO_URE_SHARE_JAVA_FOLDER)/$${F}.jar); \
+	done
+	for F in unoil; do \
+	    $(call COPYJAR,$(INSTDIR)/$(LIBO_SHARE_JAVA_FOLDER)/$${F}.jar); \
+	done
+#
+	unset JAVA_HOME && $(ANT) -quiet debug
+
+run:
+	adb shell am start -n $(APP_PACKAGE)/.ui.LibreOfficeUIActivity -e input /assets/test1.odt
diff --git a/android/experimental/LOAndroid3/build.xml b/android/experimental/LOAndroid3/build.xml
new file mode 100644
index 0000000..52d06ee
--- /dev/null
+++ b/android/experimental/LOAndroid3/build.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="LibreOfficeViewer" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <loadproperties srcFile="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
+            unless="sdk.dir"
+    />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+     in between standard targets -->
+<!--
+    <target name="-pre-build">
+    </target>
+    <target name="-pre-compile">
+    </target>
+
+    /* This is typically used for code obfuscation.
+       Compiled code location: ${out.classes.absolute.dir}
+       If this is not done in place, override ${out.dex.input.absolute.dir} */
+    <target name="-post-compile">
+    </target>
+-->
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${android.library.reference.1}/no-resource-compress.xml" />
+</project>
diff --git a/android/experimental/LOAndroid3/dummies.cxx b/android/experimental/LOAndroid3/dummies.cxx
new file mode 100644
index 0000000..5607ecf
--- /dev/null
+++ b/android/experimental/LOAndroid3/dummies.cxx
@@ -0,0 +1,75 @@
+/* -*- 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/.
+ */
+
+// Dummy implementations of the callback functions in the UI layer
+// that the LO layer calls. As this experimental Android app doesn't
+// handle any of that, these do nothing.
+
+#include <android/log.h>
+
+#include <touch/touch.h>
+
+extern "C"
+__attribute__ ((visibility("default")))
+void
+touch_ui_selection_start(MLOSelectionKind kind,
+                         const void *documentHandle,
+                         MLORect *rectangles,
+                         int rectangleCount,
+                         void *preview)
+{
+}
+
+extern "C"
+__attribute__ ((visibility("default")))
+void
+touch_ui_selection_resize_done(bool success,
+                               const void *documentHandle,
+                               MLORect *rectangles,
+                               int rectangleCount)
+{
+}
+
+extern "C"
+__attribute__ ((visibility("default")))
+void
+touch_ui_selection_none()
+{
+}
+
+
+static const char *
+dialog_kind_to_string(MLODialogKind kind)
+{
+    switch (kind) {
+    case MLODialogMessage:
+        return "MSG";
+    case MLODialogInformation:
+        return "INF";
+    case MLODialogWarning:
+        return "WRN";
+    case MLODialogError:
+        return "ERR";
+    case MLODialogQuery:
+        return "QRY";
+    default:
+        return "WTF";
+    }
+}
+
+extern "C"
+__attribute__ ((visibility("default")))
+MLODialogResult
+touch_ui_dialog_modal(MLODialogKind kind, const char *message)
+{
+    __android_log_print(ANDROID_LOG_INFO, "===>  %s: %s", dialog_kind_to_string(kind), message);
+    return MLODialogOK;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/experimental/LOAndroid3/fonts.conf b/android/experimental/LOAndroid3/fonts.conf
new file mode 100644
index 0000000..263648a
--- /dev/null
+++ b/android/experimental/LOAndroid3/fonts.conf
@@ -0,0 +1,154 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts/fonts.conf file to configure system font access -->
+<fontconfig>
+
+<!-- Font directory list -->
+
+	<dir>/system/fonts</dir>
+
+	<alias>
+		<family>serif</family>
+		<prefer>
+			<family>Droid Serif</family>
+		</prefer>
+	</alias>
+	<alias>
+		<family>sans-serif</family>
+		<prefer>
+			<family>Roboto</family>
+			<family>Droid Sans Fallback</family>
+		</prefer>
+	</alias>
+	<alias>
+		<family>monospace</family>
+		<prefer>
+			<family>Droid Sans Mono</family>
+		</prefer>
+	</alias>
+
+<!--
+  Accept deprecated 'mono' alias, replacing it with 'monospace'
+-->
+	<match target="pattern">
+		<test qual="any" name="family">
+			<string>mono</string>
+		</test>
+		<edit name="family" mode="assign">
+			<string>monospace</string>
+		</edit>
+	</match>
+
+<!--
+  Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
+-->
+	<match target="pattern">
+		<test qual="any" name="family">
+			<string>sans serif</string>
+		</test>
+		<edit name="family" mode="assign">
+			<string>sans-serif</string>
+		</edit>
+	</match>
+
+<!--
+  Accept deprecated 'sans' alias, replacing it with 'sans-serif'
+-->
+	<match target="pattern">
+		<test qual="any" name="family">
+			<string>sans</string>
+		</test>
+		<edit name="family" mode="assign">
+			<string>sans-serif</string>
+		</edit>
+	</match>
+
+<!--
+  Load local system customization file
+-->
+	<include ignore_missing="yes">conf.d</include>
+
+<!-- Font cache directory list -->
+
+	<!-- Yeah this hardcoding is wrong of course, will have to fix
+	     later to patch in proper code in fontonfig on Android to
+	     find out a good place.
+	-->
+	<cachedir>/data/data/org.libreoffice/fontconfig</cachedir>
+
+	<config>
+<!--
+  These are the default Unicode chars that are expected to be blank
+  in fonts.  All other blank chars are assumed to be broken and
+  won't appear in the resulting charsets
+ -->
+		<blank>
+			<int>0x0020</int>	<!-- SPACE -->
+			<int>0x00A0</int>	<!-- NO-BREAK SPACE -->
+			<int>0x00AD</int>	<!-- SOFT HYPHEN -->
+			<int>0x034F</int>	<!-- COMBINING GRAPHEME JOINER -->
+			<int>0x0600</int>	<!-- ARABIC NUMBER SIGN -->
+			<int>0x0601</int>	<!-- ARABIC SIGN SANAH -->
+			<int>0x0602</int>	<!-- ARABIC FOOTNOTE MARKER -->
+			<int>0x0603</int>	<!-- ARABIC SIGN SAFHA -->
+			<int>0x06DD</int>	<!-- ARABIC END OF AYAH -->
+			<int>0x070F</int>	<!-- SYRIAC ABBREVIATION MARK -->
+			<int>0x115F</int>	<!-- HANGUL CHOSEONG FILLER -->
+			<int>0x1160</int>	<!-- HANGUL JUNGSEONG FILLER -->
+			<int>0x1680</int>	<!-- OGHAM SPACE MARK -->
+			<int>0x17B4</int>	<!-- KHMER VOWEL INHERENT AQ -->
+			<int>0x17B5</int>	<!-- KHMER VOWEL INHERENT AA -->
+			<int>0x180E</int>	<!-- MONGOLIAN VOWEL SEPARATOR -->
+			<int>0x2000</int>	<!-- EN QUAD -->
+			<int>0x2001</int>	<!-- EM QUAD -->
+			<int>0x2002</int>	<!-- EN SPACE -->
+			<int>0x2003</int>	<!-- EM SPACE -->
+			<int>0x2004</int>	<!-- THREE-PER-EM SPACE -->
+			<int>0x2005</int>	<!-- FOUR-PER-EM SPACE -->
+			<int>0x2006</int>	<!-- SIX-PER-EM SPACE -->
+			<int>0x2007</int>	<!-- FIGURE SPACE -->
+			<int>0x2008</int>	<!-- PUNCTUATION SPACE -->
+			<int>0x2009</int>	<!-- THIN SPACE -->
+			<int>0x200A</int>	<!-- HAIR SPACE -->
+			<int>0x200B</int>	<!-- ZERO WIDTH SPACE -->
+			<int>0x200C</int>	<!-- ZERO WIDTH NON-JOINER -->
+			<int>0x200D</int>	<!-- ZERO WIDTH JOINER -->
+			<int>0x200E</int>	<!-- LEFT-TO-RIGHT MARK -->
+			<int>0x200F</int>	<!-- RIGHT-TO-LEFT MARK -->
+			<int>0x2028</int>	<!-- LINE SEPARATOR -->
+			<int>0x2029</int>	<!-- PARAGRAPH SEPARATOR -->
+			<int>0x202A</int>	<!-- LEFT-TO-RIGHT EMBEDDING -->
+			<int>0x202B</int>	<!-- RIGHT-TO-LEFT EMBEDDING -->
+			<int>0x202C</int>	<!-- POP DIRECTIONAL FORMATTING -->
+			<int>0x202D</int>	<!-- LEFT-TO-RIGHT OVERRIDE -->
+			<int>0x202E</int>	<!-- RIGHT-TO-LEFT OVERRIDE -->
+			<int>0x202F</int>	<!-- NARROW NO-BREAK SPACE -->
+			<int>0x205F</int>	<!-- MEDIUM MATHEMATICAL SPACE -->
+			<int>0x2060</int>	<!-- WORD JOINER -->
+			<int>0x2061</int>	<!-- FUNCTION APPLICATION -->
+			<int>0x2062</int>	<!-- INVISIBLE TIMES -->
+			<int>0x2063</int>	<!-- INVISIBLE SEPARATOR -->
+			<int>0x206A</int>	<!-- INHIBIT SYMMETRIC SWAPPING -->
+			<int>0x206B</int>	<!-- ACTIVATE SYMMETRIC SWAPPING -->
+			<int>0x206C</int>	<!-- INHIBIT ARABIC FORM SHAPING -->
+			<int>0x206D</int>	<!-- ACTIVATE ARABIC FORM SHAPING -->
+			<int>0x206E</int>	<!-- NATIONAL DIGIT SHAPES -->
+			<int>0x206F</int>	<!-- NOMINAL DIGIT SHAPES -->
+			<int>0x2800</int>	<!-- BRAILLE PATTERN BLANK -->
+			<int>0x3000</int>	<!-- IDEOGRAPHIC SPACE -->
+			<int>0x3164</int>	<!-- HANGUL FILLER -->
+			<int>0xFEFF</int>	<!-- ZERO WIDTH NO-BREAK SPACE -->
+			<int>0xFFA0</int>	<!-- HALFWIDTH HANGUL FILLER -->
+			<int>0xFFF9</int>	<!-- INTERLINEAR ANNOTATION ANCHOR -->
+			<int>0xFFFA</int>	<!-- INTERLINEAR ANNOTATION SEPARATOR -->
+			<int>0xFFFB</int>	<!-- INTERLINEAR ANNOTATION TERMINATOR -->
+		</blank>
+<!--
+  Rescan configuration every 3600 seconds when FcFontSetList is called
+ -->
+		<rescan>
+			<int>3600</int>
+		</rescan>
+	</config>
+
+</fontconfig>
diff --git a/android/experimental/LOAndroid3/jni/Android.mk b/android/experimental/LOAndroid3/jni/Android.mk
new file mode 100644
index 0000000..939a1ea
--- /dev/null
+++ b/android/experimental/LOAndroid3/jni/Android.mk
@@ -0,0 +1,8 @@
+# Needed just to satisfy ndk-gdb for now, but maybe later we will actually add
+# some JNI code here
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/android/experimental/LOAndroid3/proguard-project.txt b/android/experimental/LOAndroid3/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/android/experimental/LOAndroid3/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/android/experimental/LOAndroid3/project.properties b/android/experimental/LOAndroid3/project.properties
new file mode 100644
index 0000000..772d3c5
--- /dev/null
+++ b/android/experimental/LOAndroid3/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-15
+
+# Use the Bootstrap class
+android.library.reference.1=../../Bootstrap
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/base.png b/android/experimental/LOAndroid3/res/drawable-hdpi/base.png
new file mode 100644
index 0000000..729dbcd
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/base.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/calc.png b/android/experimental/LOAndroid3/res/drawable-hdpi/calc.png
new file mode 100644
index 0000000..a3f5fd4
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/calc.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/draw.png b/android/experimental/LOAndroid3/res/drawable-hdpi/draw.png
new file mode 100644
index 0000000..b3ee114
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/draw.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/dummy_page.png b/android/experimental/LOAndroid3/res/drawable-hdpi/dummy_page.png
new file mode 100644
index 0000000..c58d276
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/dummy_page.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/ic_launcher.png b/android/experimental/LOAndroid3/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/ic_launcher.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/ic_status_logo.png b/android/experimental/LOAndroid3/res/drawable-hdpi/ic_status_logo.png
new file mode 100644
index 0000000..d5f1669
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/ic_status_logo.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/impress.png b/android/experimental/LOAndroid3/res/drawable-hdpi/impress.png
new file mode 100644
index 0000000..5909f05
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/impress.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/lo_icon.png b/android/experimental/LOAndroid3/res/drawable-hdpi/lo_icon.png
new file mode 100644
index 0000000..2ef8641
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/lo_icon.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/main.png b/android/experimental/LOAndroid3/res/drawable-hdpi/main.png
new file mode 100644
index 0000000..7e8e2a0
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/main.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/math.png b/android/experimental/LOAndroid3/res/drawable-hdpi/math.png
new file mode 100644
index 0000000..50b8dc8
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/math.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/startcenter.png b/android/experimental/LOAndroid3/res/drawable-hdpi/startcenter.png
new file mode 100644
index 0000000..7e8e2a0
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/startcenter.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/background.png b/android/experimental/LOAndroid3/res/drawable-mdpi/background.png
new file mode 100644
index 0000000..611592b
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/background.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/base.png b/android/experimental/LOAndroid3/res/drawable-mdpi/base.png
new file mode 100644
index 0000000..729dbcd
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/base.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/calc.png b/android/experimental/LOAndroid3/res/drawable-mdpi/calc.png
new file mode 100644
index 0000000..a3f5fd4
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/calc.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/docu.png b/android/experimental/LOAndroid3/res/drawable-mdpi/docu.png
new file mode 100644
index 0000000..ab34ae5
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/docu.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/draw.png b/android/experimental/LOAndroid3/res/drawable-mdpi/draw.png
new file mode 100644
index 0000000..b3ee114
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/draw.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/ic_launcher.png b/android/experimental/LOAndroid3/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/ic_launcher.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/ic_status_logo.png b/android/experimental/LOAndroid3/res/drawable-mdpi/ic_status_logo.png
new file mode 100644
index 0000000..835fc92
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/ic_status_logo.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/impress.png b/android/experimental/LOAndroid3/res/drawable-mdpi/impress.png
new file mode 100644
index 0000000..5909f05
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/impress.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/lo_icon.png b/android/experimental/LOAndroid3/res/drawable-mdpi/lo_icon.png
new file mode 100644
index 0000000..4f3f89b
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/lo_icon.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/shadow.png b/android/experimental/LOAndroid3/res/drawable-mdpi/shadow.png
new file mode 100644
index 0000000..3ce69155
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/shadow.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-mdpi/writer.png b/android/experimental/LOAndroid3/res/drawable-mdpi/writer.png
new file mode 100644
index 0000000..2f4abcb
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-mdpi/writer.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/base.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/base.png
new file mode 100644
index 0000000..729dbcd
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/base.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/calc.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/calc.png
new file mode 100644
index 0000000..a3f5fd4
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/calc.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/draw.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/draw.png
new file mode 100644
index 0000000..b3ee114
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/draw.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/ic_launcher.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/ic_status_logo.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/ic_status_logo.png
new file mode 100644
index 0000000..c800542
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/ic_status_logo.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/impress.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/impress.png
new file mode 100644
index 0000000..5909f05
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/impress.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/writer.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/writer.png
new file mode 100644
index 0000000..2f4abcb
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/writer.png differ
diff --git a/android/experimental/LOAndroid3/res/drawable-xxhdpi/ic_launcher.png b/android/experimental/LOAndroid3/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4df1894
Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/android/experimental/LOAndroid3/res/layout/activity_main.xml b/android/experimental/LOAndroid3/res/layout/activity_main.xml
new file mode 100644
index 0000000..7b53d58
--- /dev/null
+++ b/android/experimental/LOAndroid3/res/layout/activity_main.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/main_layout"
+    android:background="#fff"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <RelativeLayout
+        android:id="@+id/gecko_layout"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_weight="1"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/android/experimental/LOAndroid3/res/menu/main.xml b/android/experimental/LOAndroid3/res/menu/main.xml
new file mode 100644
index 0000000..e9709c9
--- /dev/null
+++ b/android/experimental/LOAndroid3/res/menu/main.xml
@@ -0,0 +1,8 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context="org.libreoffice.MainActivity" >
+    <item android:id="@+id/action_settings"
+        android:title="@string/action_settings"
+        android:orderInCategory="100" />
+</menu>
diff --git a/android/experimental/LOAndroid3/res/values/colors.xml b/android/experimental/LOAndroid3/res/values/colors.xml
new file mode 100644
index 0000000..f8e207d
--- /dev/null
+++ b/android/experimental/LOAndroid3/res/values/colors.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<resources>
+  <color name="background_light">#FFECF0F3</color>
+  <color name="background_normal">#FFCED7DE</color>
+  <color name="background_private">#FF292C29</color>
+  <color name="background_tabs">#FF363B40</color>
+  <color name="highlight">#33000000</color>
+  <color name="highlight_focused">#1A000000</color>
+  <color name="highlight_dark">#33FFFFFF</color>
+  <color name="highlight_dark_focused">#1AFFFFFF</color>
+
+  <!-- highlight on shaped button: 20% white over background_tabs -->
+  <color name="highlight_shaped">#FF696D71</color>
+
+  <!-- highlight-focused on shaped button: 10% white over background_tabs -->
+  <color name="highlight_shaped_focused">#FF565B60</color>
+
+  <!-- highlight on nav button: 20% black over background_normal -->
+  <color name="highlight_nav">#FFA5ACB2</color>
+
+  <!-- highlight-focused on nav button: 10% black over background_normal -->
+  <color name="highlight_nav_focused">#FFB9C1C7</color>
+
+  <!-- highlight on private nav button: 20% white over background_private -->
+  <color name="highlight_nav_pb">#FF545654</color>
+
+  <!-- highlight-focused on private nav button: 10% white over background_private -->
+  <color name="highlight_nav_focused_pb">#FF3F423F</color>
+
+  <!--
+      Application theme colors
+  -->
+  <!-- Default colors -->
+  <color name="text_color_primary">#222222</color>
+  <color name="text_color_secondary">#777777</color>
+  <color name="text_color_tertiary">#9198A1</color>
+
+  <!-- Default inverse colors -->
+  <color name="text_color_primary_inverse">#FFFFFF</color>
+  <color name="text_color_secondary_inverse">#DDDDDD</color>
+  <color name="text_color_tertiary_inverse">#A4A7A9</color>
+
+  <!-- Disabled colors -->
+  <color name="text_color_primary_disable_only">#999999</color>
+
+  <!-- Hint colors -->
+  <color name="text_color_hint">#666666</color>
+  <color name="text_color_hint_inverse">#7F828A</color>
+
+  <!-- Highlight colors -->
+  <color name="text_color_highlight">#FF9500</color>
+  <color name="text_color_highlight_inverse">#D06BFF</color>
+
+  <!-- Link colors -->
+  <color name="text_color_link">#22629E</color>
+
+  <color name="splash_background">#000000</color>
+  <color name="splash_msgfont">#ffffff</color>
+  <color name="splash_urlfont">#000000</color>
+  <color name="splash_content">#ffffff</color>
+
+  <color name="doorhanger_text">#FF222222</color>
+  <color name="doorhanger_link">#FF2AA1FE</color>
+  <color name="doorhanger_divider_light">#FFD1D5DA</color>
+  <color name="doorhanger_divider_dark">#FFB3C2CE</color>
+  <color name="doorhanger_background_dark">#FFDDE4EA</color>
+
+  <color name="validation_message_text">#ffffff</color>
+  <color name="url_bar_text_highlight">#FFFF9500</color>
+  <color name="url_bar_text_highlight_pb">#FFD06BFF</color>
+  <color name="suggestion_primary">#dddddd</color>
+  <color name="suggestion_pressed">#bbbbbb</color>
+  <color name="tab_row_pressed">#4D000000</color>
+  <color name="dialogtitle_textcolor">#ffffff</color>
+
+  <color name="textbox_background">#FFF</color>
+  <color name="textbox_background_disabled">#DDD</color>
+  <color name="textbox_stroke">#000</color>
+  <color name="textbox_stroke_disabled">#666</color>
+
+  <color name="url_bar_urltext">#A6A6A6</color>
+  <color name="url_bar_domaintext">#000</color>
+  <color name="url_bar_domaintext_private">#FFF</color>
+  <color name="url_bar_blockedtext">#b14646</color>
+  <color name="url_bar_shadow">#12000000</color>
+
+  <color name="home_last_tab_bar_bg">#FFF5F7F9</color>
+
+  <color name="panel_grid_item_image_background">#D1D9E1</color>
+</resources>
+
diff --git a/android/experimental/LOAndroid3/res/values/dimens.xml b/android/experimental/LOAndroid3/res/values/dimens.xml
new file mode 100644
index 0000000..47c8224
--- /dev/null
+++ b/android/experimental/LOAndroid3/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/android/experimental/LOAndroid3/res/values/strings.xml b/android/experimental/LOAndroid3/res/values/strings.xml
new file mode 100644
index 0000000..93431ed
--- /dev/null
+++ b/android/experimental/LOAndroid3/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">LibreOffice</string>
+    <string name="action_settings">Settings</string>
+
+</resources>
diff --git a/android/experimental/LOAndroid3/res/values/styles.xml b/android/experimental/LOAndroid3/res/values/styles.xml
new file mode 100644
index 0000000..ff6c9d2
--- /dev/null
+++ b/android/experimental/LOAndroid3/res/values/styles.xml
@@ -0,0 +1,8 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+    </style>
+
+</resources>
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java
new file mode 100644
index 0000000..bf4f98b
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java
@@ -0,0 +1,67 @@
+package org.libreoffice;
+
+import android.graphics.Rect;
+import android.util.Log;
+
+import org.mozilla.gecko.gfx.IntSize;
+import org.mozilla.gecko.gfx.ViewportMetrics;
+
+public class LOEvent {
+
+    public static final int SIZE_CHANGED = 1;
+    public static final int TILE_SIZE = 2;
+    public static final int VIEWPORT = 3;
+    public static final int DRAW = 4;
+
+    private ViewportMetrics mViewportMetrics;
+
+    public int mType;
+    private String mTypeString;
+
+    ViewportMetrics viewportMetrics;
+
+    public LOEvent(int type, int width, int height, int widthPixels, int heightPixels, int tileWidth, int tileHeight) {
+        mType = type;
+        mTypeString = "Size Changed";
+    }
+
+    public LOEvent(int type, IntSize tileSize) {
+        mType = type;
+        mTypeString = "Tile size";
+    }
+
+    public LOEvent(int type, ViewportMetrics viewportMetrics) {
+        mType = type;
+        mTypeString = "Viewport";
+        mViewportMetrics = viewportMetrics;
+    }
+
+    public LOEvent(int type, Rect rect) {
+        mType = type;
+        mTypeString = "Draw";
+    }
+
+    public static LOEvent draw(Rect rect) {
+        return new LOEvent(DRAW, rect);
+    }
+
+    public static LOEvent sizeChanged(int width, int height, int widthPixels, int heightPixels, int tileWidth, int tileHeight) {
+        return new LOEvent(SIZE_CHANGED, width, height, widthPixels, heightPixels, tileWidth, tileHeight);
+    }
+
+    public static LOEvent tileSize(IntSize tileSize) {
+        return new LOEvent(TILE_SIZE, tileSize);
+    }
+
+    public static LOEvent viewport(ViewportMetrics viewportMetrics) {
+        return new LOEvent(VIEWPORT, viewportMetrics);
+    }
+
+    public String getTypeString() {
+        return mTypeString;
+    }
+
+    public ViewportMetrics getViewport() {
+        return mViewportMetrics;
+    }
+}
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitShell.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitShell.java
new file mode 100644
index 0000000..9dde790
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitShell.java
@@ -0,0 +1,131 @@
+package org.libreoffice;
+
+
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
+import org.mozilla.gecko.gfx.IntSize;
+import org.mozilla.gecko.gfx.LayerController;
+import org.mozilla.gecko.gfx.LayerView;
+
+import java.nio.ByteBuffer;
+
+public class LOKitShell {
+    private static final String LOGTAG = LOKitShell.class.getSimpleName();
+
+    public static int getDpi() {
+        return 96;
+    }
+
+    public static int getScreenDepth() {
+        return 24;
+    }
+
+    public static float computeRenderIntegrity() {
+        return 0.0f;
+    }
+
+    public static ByteBuffer allocateDirectBuffer(int size) {
+        if (size <= 0) {
+            throw new IllegalArgumentException("Invalid size " + size);
+        }
+
+        ByteBuffer directBuffer = ByteBuffer.allocateDirect(size);
+        //ByteBuffer directBuffer = nativeAllocateDirectBuffer(size);
+        if (directBuffer == null) {
+            throw new OutOfMemoryError("allocateDirectBuffer() returned null");
+        } else if (!directBuffer.isDirect()) {
+            throw new AssertionError("allocateDirectBuffer() did not return a direct buffer");
+        }
+
+        return directBuffer;
+    }
+
+
+    public static void freeDirectBuffer(ByteBuffer buffer) {
+        if (buffer == null) {
+            return;
+        }
+
+        if (!buffer.isDirect()) {
+            throw new IllegalArgumentException("buffer must be direct");
+        }
+        //nativeFreeDirectBuffer(buffer);
+        return ;
+    }
+
+    public static void bindWidgetTexture() {
+    }
+
+    public static void sendEvent(LOEvent event) {
+        Log.i(LOGTAG, "Event: " + event.getTypeString());
+    }
+
+    public static void runGecko(String apkPath, String args, String url, boolean restoreSession) {
+        // run gecko -- it will spawn its own thread
+        // GeckoAppShell.nativeInit();
+
+        Log.i(LOGTAG, "post native init");
+
+        // Tell Gecko where the target byte buffer is for rendering
+        //GeckoAppShell.setSoftwareLayerClient(GeckoApp.mAppContext.getSoftwareLayerClient());
+
+        Log.i(LOGTAG, "setSoftwareLayerClient called");
+
+        // First argument is the .apk path
+        String combinedArgs = apkPath + " -greomni " + apkPath;
+        if (args != null)
+            combinedArgs += " " + args;
+        if (url != null)
+            combinedArgs += " -remote " + url;
+        if (restoreSession)
+            combinedArgs += " -restoresession";
+
+        DisplayMetrics metrics = new DisplayMetrics();
+        LibreOfficeMainActivity.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        combinedArgs += " -width " + metrics.widthPixels + " -height " + metrics.heightPixels;
+
+        LibreOfficeMainActivity.mAppContext.runOnUiThread(new Runnable() {
+            public void run() {
+                geckoLoaded();
+            }
+        });
+
+        //LOKitShell.nativeRun(combinedArgs);
+    }
+
+    // Called on the UI thread after Gecko loads.
+    private static void geckoLoaded() {
+        /*final LayerController layerController = LibreOfficeMainActivity.mAppContext.getLayerController();
+        LayerView v = layerController.getView();
+        mInputConnection = GeckoInputConnection.create(v);
+        v.setInputConnectionHandler(mInputConnection);
+
+        layerController.setOnTouchListener(new View.OnTouchListener() {
+            public boolean onTouch(View view, MotionEvent event) {
+                if (event == null)
+                    return true;
+                GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
+                return true;
+            }
+        });
+
+        layerController.notifyLayerClientOfGeometryChange();*/
+    }
+
+    public static void viewSizeChanged() {
+    }
+
+    public static void scheduleComposite() {
+    }
+
+    public static void schedulePauseComposition() {
+    }
+
+    public static void scheduleResumeComposition() {
+
+    }
+}
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
new file mode 100644
index 0000000..ea3472b
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
@@ -0,0 +1,135 @@
+package org.libreoffice;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.JsonWriter;
+
+import org.mozilla.gecko.gfx.ViewportMetrics;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.Random;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class LOKitThread extends Thread {
+    private static final String LOGTAG = "GeckoThread";
+
+    public ConcurrentLinkedQueue<LOEvent> gEvents = new ConcurrentLinkedQueue<LOEvent>();
+    private ViewportMetrics mViewportMetrics;
+    private Random rand = new Random();
+
+    LOKitThread() {
+    }
+
+    private boolean draw() throws InterruptedException {
+        final LibreOfficeMainActivity application = LibreOfficeMainActivity.mAppContext;
+
+        Bitmap bitmap = application.getLayerClient().getLayerController().getDrawable("docu");
+        //bitmap = convert(bitmap, Bitmap.Config.ARGB_8888);
+
+        StringWriter stringWriter = new StringWriter();
+
+        try {
+            JsonWriter writer = new JsonWriter(stringWriter);
+            writer.beginObject();
+            if (mViewportMetrics == null) {
+                writer.name("x").value(0);
+                writer.name("y").value(0);
+                writer.name("width").value(bitmap.getWidth());
+                writer.name("height").value(bitmap.getHeight());
+                writer.name("pageWidth").value(bitmap.getWidth());
+                writer.name("pageHeight").value(bitmap.getHeight());
+                writer.name("offsetX").value(0);
+                writer.name("offsetY").value(0);
+                writer.name("zoom").value(0.5);
+            } else {
+                writer.name("x").value(mViewportMetrics.getOrigin().x);
+                writer.name("y").value(mViewportMetrics.getOrigin().y);
+                writer.name("width").value(mViewportMetrics.getSize().width);
+                writer.name("height").value(mViewportMetrics.getSize().height);
+                writer.name("pageWidth").value(mViewportMetrics.getPageSize().width);
+                writer.name("pageHeight").value(mViewportMetrics.getPageSize().height);
+                writer.name("offsetX").value(mViewportMetrics.getViewportOffset().x);
+                writer.name("offsetY").value(mViewportMetrics.getViewportOffset().y);
+                writer.name("zoom").value(mViewportMetrics.getZoomFactor());
+            }
+            writer.name("backgroundColor").value("rgb(255,255,255)");
+            writer.endObject();
+            writer.close();
+        } catch (IOException ex) {
+        }
+
+        Rect bufferRect = application.getLayerClient().beginDrawing(bitmap.getWidth(), bitmap.getHeight(), 256, 256, stringWriter.toString(), false);
+
+        if (bufferRect == null) {
+            return false;
+        }
+            ByteBuffer buffer = application.getLayerClient().lockBuffer();
+            bitmap.copyPixelsToBuffer(buffer.asIntBuffer());
+            application.getLayerClient().unlockBuffer();
+
+            application.getLayerClient().endDrawing(0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+            application.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    application.getLayerClient().handleMessage("Viewport:UpdateLater", null);
+                }
+            });
+        return true;
+    }
+
+    private short convertTo16Bit(int color) {
+        int r = Color.red(color) >> 3, g = Color.green(color) >> 2, b = Color.blue(color) >> 3;
+        int c = ((r << 11) | (g << 5) | b);
+        // Swap endianness.
+        return (short) ((c >> 8) | ((c & 0xff) << 8));
+    }
+
+    private Bitmap convert(Bitmap bitmap, Bitmap.Config config) {
+        Bitmap convertedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), config);
+        Canvas canvas = new Canvas(convertedBitmap);
+        Paint paint = new Paint();
+        paint.setColor(Color.BLACK);
+        canvas.drawBitmap(bitmap, 0, 0, paint);
+        return convertedBitmap;
+    }
+
+
+    public void run() {
+        try {
+            boolean drawn = false;
+            while (true) {
+
+                if (!gEvents.isEmpty()) {
+                    processEvent(gEvents.poll());
+                } else {
+                    if (!drawn) {
+                        drawn = draw();
+                    }
+                    Thread.sleep(100L);
+                }
+            }
+        } catch (InterruptedException ex) {
+        }
+    }
+
+    private void processEvent(LOEvent event) throws InterruptedException {
+        switch (event.mType) {
+            case LOEvent.VIEWPORT:
+                mViewportMetrics = event.getViewport();
+                break;
+            case LOEvent.DRAW:
+                draw();
+                break;
+            case LOEvent.SIZE_CHANGED:
+                break;
+        }
+    }
+
+
+}
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java
new file mode 100644
index 0000000..d475844
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java
@@ -0,0 +1,145 @@
+package org.libreoffice;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
+import org.mozilla.gecko.gfx.LayerController;
+import org.mozilla.gecko.gfx.LayerView;
+
+import org.libreoffice.android.Bootstrap;
+
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.uno.UnoRuntime;
+
+public class LibreOfficeMainActivity extends Activity {
+
+    private static final String LOGTAG = "LibreOfficeMainActivity";
+
+    private LinearLayout mMainLayout;
+    private RelativeLayout mGeckoLayout;
+    private static LayerController mLayerController;
+    private static GeckoSoftwareLayerClient mLayerClient;
+    private static LOKitThread sLOKitThread;
+
+    private XComponentContext context;
+    private XMultiComponentFactory mcf;
+    private XComponentLoader componentLoader;
+
+    public static LibreOfficeMainActivity mAppContext;
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        int id = item.getItemId();
+        if (id == R.id.action_settings) {
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    public DisplayMetrics getDisplayMetrics() {
+        DisplayMetrics metrics = new DisplayMetrics();
+        getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        return metrics;
+    }
+
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        mAppContext = this;
+
+        super.onCreate(savedInstanceState);
+
+        try {
+            Bootstrap.setup(this);
+            Bootstrap.putenv("SAL_LOG=+WARN+INFO-INFO.legacy.osl");
+
+            setContentView(R.layout.activity_main);
+
+            Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onCreate");
+
+            String input = "/assets/test1.odt";
+
+            String[] argv = { "lo-document-loader", input };
+
+            Bootstrap.setCommandArgs(argv);
+
+            Bootstrap.initVCL();
+
+            context = com.sun.star.comp.helper.Bootstrap.defaultBootstrap_InitialComponentContext();
+
+            Log.i(LOGTAG, "context is" + (context!=null ? " not" : "") + " null");
+
+            mcf = context.getServiceManager();
+
+            Log.i(LOGTAG, "mcf is" + (mcf!=null ? " not" : "") + " null");
+
+            Object desktop = mcf.createInstanceWithContext("com.sun.star.frame.Desktop", context);
+            Log.i(LOGTAG, "desktop is" + (desktop!=null ? " not" : "") + " null");
+
+            componentLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, desktop);
+            Log.i(LOGTAG, "componentLoader is" + (componentLoader!=null ? " not" : "") + " null");
+
+        } catch (Exception e) {
+            e.printStackTrace(System.err);
+            //finish();
+        }
+
+        setContentView(R.layout.activity_main);
+
+        // setup gecko layout
+        mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout);
+        mMainLayout = (LinearLayout) findViewById(R.id.main_layout);
+
+
+        if (mLayerController == null) {
+            mLayerController = new LayerController(this);
+
+            Log.e(LOGTAG, "### Creating GeckoSoftwareLayerClient");
+            mLayerClient = new GeckoSoftwareLayerClient(this);
+            Log.e(LOGTAG, "### Done creating GeckoSoftwareLayerClient");
+
+            mLayerController.setLayerClient(mLayerClient);
+            mGeckoLayout.addView(mLayerController.getView(), 0);
+        }
+
+        mLayerController.notifyLayerClientOfGeometryChange();
+
+        sLOKitThread = new LOKitThread();
+        sLOKitThread.start();
+
+
+        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
+    }
+
+    public static GeckoSoftwareLayerClient getLayerClient() {
+        return mLayerClient;
+    }
+
+    public static LayerController getLayerController() {
+        return mLayerController;
+    }
+}
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/GeckoEventListener.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/GeckoEventListener.java
new file mode 100644
index 0000000..670513f
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/GeckoEventListener.java
@@ -0,0 +1,44 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sriram Ramasubramanian <sriram at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import org.json.JSONObject;
+
+public interface GeckoEventListener {
+    public void handleMessage(String event, JSONObject message);
+}
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/BufferedCairoImage.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/BufferedCairoImage.java
new file mode 100644
index 0000000..b6c3977
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/BufferedCairoImage.java
@@ -0,0 +1,105 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import android.graphics.Bitmap;
+
+import org.libreoffice.LOKitShell;
+
+import java.nio.ByteBuffer;
+
+//import org.mozilla.gecko.GeckoAppShell;
+
+/**
+ * A Cairo image that simply saves a buffer of pixel data.
+ */
+public class BufferedCairoImage extends CairoImage {
+    private ByteBuffer mBuffer;
+    private IntSize mSize;
+    private int mFormat;
+    private boolean mNeedToFreeBuffer = false;
+
+    /**
+     * Creates a buffered Cairo image from a byte buffer.
+     */
+    public BufferedCairoImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
+        mBuffer = inBuffer;
+        mSize = new IntSize(inWidth, inHeight);
+        mFormat = inFormat;
+    }
+
+    /**
+     * Creates a buffered Cairo image from an Android bitmap.
+     */
+    public BufferedCairoImage(Bitmap bitmap) {
+        mFormat = CairoUtils.bitmapConfigToCairoFormat(bitmap.getConfig());
+        mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
+        mNeedToFreeBuffer = true;
+        // XXX Why is this * 4? Shouldn't it depend on mFormat?
+        mBuffer = /*GeckoAppShell*/LOKitShell.allocateDirectBuffer(mSize.getArea() * 4);
+
+        bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            if (mNeedToFreeBuffer && mBuffer != null)
+                /*GeckoAppShell*/ LOKitShell.freeDirectBuffer(mBuffer);
+            mNeedToFreeBuffer = false;
+            mBuffer = null;
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public ByteBuffer getBuffer() {
+        return mBuffer;
+    }
+
+    @Override
+    public IntSize getSize() {
+        return mSize;
+    }
+
+    @Override
+    public int getFormat() {
+        return mFormat;
+    }
+}
+
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoGLInfo.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoGLInfo.java
new file mode 100644
index 0000000..bd4eedc
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoGLInfo.java
@@ -0,0 +1,72 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Information needed to render Cairo bitmaps using OpenGL ES.
+ */
+public class CairoGLInfo {
+    public final int internalFormat;
+    public final int format;
+    public final int type;
+
+    public CairoGLInfo(int cairoFormat) {
+        switch (cairoFormat) {
+            case CairoImage.FORMAT_ARGB32:
+                internalFormat = format = GL10.GL_RGBA;
+                type = GL10.GL_UNSIGNED_BYTE;
+                break;
+            case CairoImage.FORMAT_RGB24:
+                internalFormat = format = GL10.GL_RGB;
+                type = GL10.GL_UNSIGNED_BYTE;
+                break;
+            case CairoImage.FORMAT_RGB16_565:
+                internalFormat = format = GL10.GL_RGB;
+                type = GL10.GL_UNSIGNED_SHORT_5_6_5;
+                break;
+            case CairoImage.FORMAT_A8:
+            case CairoImage.FORMAT_A1:
+                throw new RuntimeException("Cairo FORMAT_A1 and FORMAT_A8 unsupported");
+            default:
+                throw new RuntimeException("Unknown Cairo format");
+        }
+    }
+}
+
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoImage.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoImage.java
new file mode 100644
index 0000000..06c389d
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoImage.java
@@ -0,0 +1,58 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import java.nio.ByteBuffer;
+
+/*
+ * A bitmap with pixel data in one of the formats that Cairo understands.
+ */
+public abstract class CairoImage {
+    public abstract ByteBuffer getBuffer();
+
+    public abstract IntSize getSize();
+    public abstract int getFormat();
+
+    public static final int FORMAT_INVALID = -1;
+    public static final int FORMAT_ARGB32 = 0;
+    public static final int FORMAT_RGB24 = 1;
+    public static final int FORMAT_A8 = 2;
+    public static final int FORMAT_A1 = 3;
+    public static final int FORMAT_RGB16_565 = 4;
+}
+
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoUtils.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoUtils.java
new file mode 100644
index 0000000..00bd896
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CairoUtils.java
@@ -0,0 +1,85 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import org.mozilla.gecko.gfx.CairoImage;
+import android.graphics.Bitmap;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Utility methods useful when displaying Cairo bitmaps using OpenGL ES.
+ */
+public class CairoUtils {
+    private CairoUtils() { /* Don't call me. */ }
+
+    public static int bitsPerPixelForCairoFormat(int cairoFormat) {
+        switch (cairoFormat) {
+        case CairoImage.FORMAT_A1:          return 1;
+        case CairoImage.FORMAT_A8:          return 8;
+        case CairoImage.FORMAT_RGB16_565:   return 16;
+        case CairoImage.FORMAT_RGB24:       return 24;
+        case CairoImage.FORMAT_ARGB32:      return 32;
+        default:
+            throw new RuntimeException("Unknown Cairo format");
+        }
+    }
+
+    public static int bitmapConfigToCairoFormat(Bitmap.Config config) {
+        if (config == null)
+            return CairoImage.FORMAT_ARGB32;    /* Droid Pro fix. */
+
+        switch (config) {
+        case ALPHA_8:   return CairoImage.FORMAT_A8;
+        case ARGB_4444: throw new RuntimeException("ARGB_444 unsupported");
+        case ARGB_8888: return CairoImage.FORMAT_ARGB32;
+        case RGB_565:   return CairoImage.FORMAT_RGB16_565;
+        default:        throw new RuntimeException("Unknown Skia bitmap config");
+        }
+    }
+
+    public static Bitmap.Config cairoFormatTobitmapConfig(int format) {
+        switch (format) {
+        case CairoImage.FORMAT_A8:        return Bitmap.Config.ALPHA_8;
+        case CairoImage.FORMAT_ARGB32:    return Bitmap.Config.ARGB_8888;
+        case CairoImage.FORMAT_RGB16_565: return Bitmap.Config.RGB_565;
+        default:
+            throw new RuntimeException("Unknown CairoImage format");
+        }
+    }
+}
+
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CheckerboardImage.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CheckerboardImage.java
new file mode 100644
index 0000000..392d7e8
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/CheckerboardImage.java
@@ -0,0 +1,170 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import org.libreoffice.LOKitShell;
+import android.graphics.Color;
+import java.nio.ByteBuffer;
+import java.nio.ShortBuffer;
+import java.util.Arrays;
+
+/** A Cairo image that displays a tinted checkerboard. */
+public class CheckerboardImage extends CairoImage {
+    // The width and height of the checkerboard tile.
+    private static final int SIZE = 16;
+    // The pixel format of the checkerboard tile.
+    private static final int FORMAT = CairoImage.FORMAT_RGB16_565;
+    // The color to mix in to tint the background color.
+    private static final int TINT_COLOR = Color.GRAY;
+    // The amount to mix in.
+    private static final float TINT_OPACITY = 0.4f;
+
+    private ByteBuffer mBuffer;
+    private int mMainColor;
+    private boolean mShowChecks;
+
+    /** Creates a new checkerboard image. */
+    public CheckerboardImage() {
+        int bpp = CairoUtils.bitsPerPixelForCairoFormat(FORMAT);
+        mBuffer = LOKitShell.allocateDirectBuffer(SIZE * SIZE * bpp / 8);
+        update(true, Color.WHITE);
+    }
+
+    /** Returns the current color of the checkerboard. */
+    public int getColor() {
+        return mMainColor;
+    }
+
+    /** Returns whether or not we are currently showing checks on the checkerboard. */
+    public boolean getShowChecks() {
+        return mShowChecks;
+    }
+
+    /** Updates the checkerboard image. If showChecks is true, then create a
+     checkerboard image that is tinted to the color. Otherwise just return a flat
+     image of the color. */
+    public void update(boolean showChecks, int color) {
+        mMainColor = color;
+        mShowChecks = showChecks;
+
+        short mainColor16 = convertTo16Bit(mMainColor);
+
+        mBuffer.rewind();
+        ShortBuffer shortBuffer = mBuffer.asShortBuffer();
+
+        if (!mShowChecks) {
+            short color16 = convertTo16Bit(mMainColor);
+            short[] fillBuffer = new short[SIZE];
+            Arrays.fill(fillBuffer, color16);
+
+            for (int i = 0; i < SIZE; i++) {
+                shortBuffer.put(fillBuffer);
+            }
+
+            return;
+        }
+
+        short tintColor16 = convertTo16Bit(tint(mMainColor));
+
+        short[] mainPattern = new short[SIZE / 2], tintPattern = new short[SIZE / 2];
+        Arrays.fill(mainPattern, mainColor16);
+        Arrays.fill(tintPattern, tintColor16);
+
+        // The checkerboard pattern looks like this:
+        //
+        // +---+---+
+        // | N | T |  N = normal
+        // +---+---+  T = tinted
+        // | T | N |
+        // +---+---+
+
+        for (int i = 0; i < SIZE / 2; i++) {
+            shortBuffer.put(mainPattern);
+            shortBuffer.put(tintPattern);
+        }
+        for (int i = SIZE / 2; i < SIZE; i++) {
+            shortBuffer.put(tintPattern);
+            shortBuffer.put(mainPattern);
+        }
+    }
+
+    // Tints the given color appropriately and returns the tinted color.
+    private int tint(int color) {
+        float negTintOpacity = 1.0f - TINT_OPACITY;
+        float r = Color.red(color) * negTintOpacity + Color.red(TINT_COLOR) * TINT_OPACITY;
+        float g = Color.green(color) * negTintOpacity + Color.green(TINT_COLOR) * TINT_OPACITY;
+        float b = Color.blue(color) * negTintOpacity + Color.blue(TINT_COLOR) * TINT_OPACITY;
+        return Color.rgb(Math.round(r), Math.round(g), Math.round(b));
+    }
+
+    // Converts a 32-bit ARGB color to 16-bit R5G6B5, truncating values and discarding the alpha
+    // channel.
+    private short convertTo16Bit(int color) {
+        int r = Color.red(color) >> 3, g = Color.green(color) >> 2, b = Color.blue(color) >> 3;
+        int c = ((r << 11) | (g << 5) | b);
+        // Swap endianness.
+        return (short)((c >> 8) | ((c & 0xff) << 8));
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mBuffer != null) {
+                LOKitShell.freeDirectBuffer(mBuffer);
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public ByteBuffer getBuffer() {
+        return mBuffer;
+    }
+
+    @Override
+    public IntSize getSize() {
+        return new IntSize(SIZE, SIZE);
+    }
+
+    @Override
+    public int getFormat() {
+        return FORMAT;
+    }
+}
+
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/FlexibleGLSurfaceView.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/FlexibleGLSurfaceView.java
new file mode 100644
index 0000000..dc20077
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/FlexibleGLSurfaceView.java
@@ -0,0 +1,218 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+//import org.mozilla.gecko.GeckoApp;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import org.libreoffice.LibreOfficeMainActivity;
+
+public class FlexibleGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+    private static final String LOGTAG = "GeckoFlexibleGLSurfaceView";
+
+    private GLSurfaceView.Renderer mRenderer;
+    private GLThread mGLThread; // Protected by this class's monitor.
+    private GLController mController;
+    private Listener mListener;
+
+    public FlexibleGLSurfaceView(Context context) {
+        super(context);
+        init();
+    }
+
+    public FlexibleGLSurfaceView(Context context, AttributeSet attributeSet) {
+        super(context, attributeSet);
+        init();
+    }
+
+    public void init() {
+        SurfaceHolder holder = getHolder();
+        holder.addCallback(this);
+        holder.setFormat(PixelFormat.RGB_565);
+
+        mController = new GLController(this);
+    }
+
+    public void setRenderer(GLSurfaceView.Renderer renderer) {
+        mRenderer = renderer;
+    }
+
+    public GLSurfaceView.Renderer getRenderer() {
+        return mRenderer;
+    }
+
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    public synchronized void requestRender() {
+        if (mGLThread != null) {
+            mGLThread.renderFrame();
+        }
+        if (mListener != null) {
+            mListener.renderRequested();
+        }
+    }
+
+    /**
+     * Creates a Java GL thread. After this is called, the FlexibleGLSurfaceView may be used just
+     * like a GLSurfaceView. It is illegal to access the controller after this has been called.
+     */
+    public synchronized void createGLThread() {
+        if (mGLThread != null) {
+            throw new FlexibleGLSurfaceViewException("createGLThread() called with a GL thread " +
+                    "already in place!");
+        }
+
+        Log.e(LOGTAG, "### Creating GL thread!");
+        mGLThread = new GLThread(mController);
+        mGLThread.start();
+        notifyAll();
+    }
+
+    /**
+     * Destroys the Java GL thread. Returns a Thread that completes when the Java GL thread is
+     * fully shut down.
+     */
+    public synchronized Thread destroyGLThread() {
+        // Wait for the GL thread to be started.
+        Log.e(LOGTAG, "### Waiting for GL thread to be created...");
+        while (mGLThread == null) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        Log.e(LOGTAG, "### Destroying GL thread!");
+        Thread glThread = mGLThread;
+        mGLThread.shutdown();
+        mGLThread = null;
+        return glThread;
+    }
+
+    public synchronized void recreateSurface() {
+        if (mGLThread == null) {
+            throw new FlexibleGLSurfaceViewException("recreateSurface() called with no GL " +
+                    "thread active!");
+        }
+
+        mGLThread.recreateSurface();
+    }
+
+    public synchronized GLController getGLController() {
+        if (mGLThread != null) {
+            throw new FlexibleGLSurfaceViewException("getGLController() called with a GL thread " +
+                    "active; shut down the GL thread first!");
+        }
+
+        return mController;
+    }
+
+    public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width,
+                                            int height) {
+        mController.sizeChanged(width, height);
+        if (mGLThread != null) {
+            mGLThread.surfaceChanged(width, height);
+        }
+
+        if (mListener != null) {
+            mListener.surfaceChanged(width, height);
+        }
+    }
+
+    public synchronized void surfaceCreated(SurfaceHolder holder) {
+        mController.surfaceCreated();
+        if (mGLThread != null) {
+            mGLThread.surfaceCreated();
+        }
+    }
+
+    public synchronized void surfaceDestroyed(SurfaceHolder holder) {
+        mController.surfaceDestroyed();
+        if (mGLThread != null) {
+            mGLThread.surfaceDestroyed();
+        }
+
+        if (mListener != null) {
+            mListener.compositionPauseRequested();
+        }
+    }
+
+    // Called from the compositor thread
+    public static GLController registerCxxCompositor() {
+        try {
+            Log.e(LOGTAG, "### registerCxxCompositor point A");
+            System.out.println("register layer comp");
+            Log.e(LOGTAG, "### registerCxxCompositor point B");
+            FlexibleGLSurfaceView flexView = (FlexibleGLSurfaceView) /*GeckoApp*/LibreOfficeMainActivity.mAppContext.getLayerController().getView();
+            Log.e(LOGTAG, "### registerCxxCompositor point C: " + flexView);
+            try {
+                flexView.destroyGLThread().join();
+            } catch (InterruptedException e) {}
+            Log.e(LOGTAG, "### registerCxxCompositor point D: " + flexView.getGLController());
+            return flexView.getGLController();
+        } catch (Exception e) {
+            Log.e(LOGTAG, "### Exception! " + e);
+            return null;
+        }
+    }
+
+    public interface Listener {
+        void renderRequested();
+        void compositionPauseRequested();
+        void compositionResumeRequested();
+        void surfaceChanged(int width, int height);
+    }
+
+    public static class FlexibleGLSurfaceViewException extends RuntimeException {
+        public static final long serialVersionUID = 1L;
+
+        FlexibleGLSurfaceViewException(String e) {
+            super(e);
+        }
+    }
+}
+
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/FloatSize.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/FloatSize.java
new file mode 100644
index 0000000..5fb73ec
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/FloatSize.java
@@ -0,0 +1,99 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *   Chris Lord <chrislord.net at gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.gecko.util.FloatUtils;
+
+public class FloatSize {
+    public final float width, height;
+
+    public FloatSize(FloatSize size) {
+        width = size.width;
+        height = size.height;
+    }
+
+    public FloatSize(IntSize size) {
+        width = size.width;
+        height = size.height;
+    }
+
+    public FloatSize(float aWidth, float aHeight) {
+        width = aWidth;
+        height = aHeight;
+    }
+
+    public FloatSize(JSONObject json) {
+        try {
+            width = (float) json.getDouble("width");
+            height = (float) json.getDouble("height");
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "(" + width + "," + height + ")";
+    }
+
+    public boolean isPositive() {
+        return (width > 0 && height > 0);
+    }
+
+    public boolean fuzzyEquals(FloatSize size) {
+        return (FloatUtils.fuzzyEquals(size.width, width) &&
+                FloatUtils.fuzzyEquals(size.height, height));
+    }
+
+    public FloatSize scale(float factor) {
+        return new FloatSize(width * factor, height * factor);
+    }
+
+    /*
+     * Returns the size that represents a linear transition between this size and `to` at time `t`,
+     * which is on the scale [0, 1).
+     */
+    public FloatSize interpolate(FloatSize to, float t) {
+        return new FloatSize(FloatUtils.interpolate(width, to.width, t),
+                FloatUtils.interpolate(height, to.height, t));
+    }
+}
+
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GLController.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GLController.java
new file mode 100644
index 0000000..e8f2012
--- /dev/null
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GLController.java
@@ -0,0 +1,279 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Patrick Walton <pcwalton at mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+
+public class GLController {
+    private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+    private static final String LOGTAG = "GeckoGLController";
+
+    private FlexibleGLSurfaceView mView;
+    private int mGLVersion;
+    private boolean mSurfaceValid;
+    private int mWidth, mHeight;
+
+    private EGL10 mEGL;
+    private EGLDisplay mEGLDisplay;
+    private EGLConfig mEGLConfig;
+    private EGLContext mEGLContext;
+    private EGLSurface mEGLSurface;
+
+    private GL mGL;
+
+    private static final int LOCAL_EGL_OPENGL_ES2_BIT = 4;
+
+    private static final int[] CONFIG_SPEC = {
+            EGL10.EGL_RED_SIZE, 5,
+            EGL10.EGL_GREEN_SIZE, 6,
+            EGL10.EGL_BLUE_SIZE, 5,
+            EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
+            EGL10.EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
+            EGL10.EGL_NONE
+    };
+
+    public GLController(FlexibleGLSurfaceView view) {
+        mView = view;
+        mGLVersion = 2;
+        mSurfaceValid = false;
+    }
+
+    public void setGLVersion(int version) {
+        mGLVersion = version;
+    }
+
+    /** You must call this on the same thread you intend to use OpenGL on. */
+    public void initGLContext() {
+        initEGLContext();
+        createEGLSurface();
+    }
+
+    public void disposeGLContext() {
+        if (!mEGL.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,
+                EGL10.EGL_NO_CONTEXT)) {
+            throw new GLControllerException("EGL context could not be released!");
+        }
+
+        if (mEGLSurface != null) {
+            if (!mEGL.eglDestroySurface(mEGLDisplay, mEGLSurface)) {
+                throw new GLControllerException("EGL surface could not be destroyed!");
+            }
+
+            mEGLSurface = null;
+        }
+
+        if (mEGLContext == null) {
+            if (!mEGL.eglDestroyContext(mEGLDisplay, mEGLContext)) {
+                throw new GLControllerException("EGL context could not be destroyed!");
+            }
+
+            mGL = null;
+            mEGLDisplay = null;
+            mEGLConfig = null;
+            mEGLContext = null;
+        }
+    }
+
+    public GL getGL()                       { return mEGLContext.getGL(); }
+    public EGLDisplay getEGLDisplay()       { return mEGLDisplay;         }
+    public EGLConfig getEGLConfig()         { return mEGLConfig;          }
+    public EGLContext getEGLContext()       { return mEGLContext;         }
+    public EGLSurface getEGLSurface()       { return mEGLSurface;         }
+    public FlexibleGLSurfaceView getView()  { return mView;               }
+
+    public boolean hasSurface() {
+        return mEGLSurface != null;
+    }
+
+    public boolean swapBuffers() {
+        return mEGL.eglSwapBuffers(mEGLDisplay, mEGLSurface);
+    }
+
+    public boolean checkForLostContext() {
+        if (mEGL.eglGetError() != EGL11.EGL_CONTEXT_LOST) {
+            return false;
+        }
+
+        mEGLDisplay = null;
+        mEGLConfig = null;
+        mEGLContext = null;
+        mEGLSurface = null;
+        mGL = null;
+        return true;
+    }
+
+    public synchronized void waitForValidSurface() {
+        while (!mSurfaceValid) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public synchronized int getWidth() {
+        return mWidth;
+    }
+
+    public synchronized int getHeight() {
+        return mHeight;
+    }
+
+    synchronized void surfaceCreated() {
+        mSurfaceValid = true;
+        notifyAll();
+    }
+
+    synchronized void surfaceDestroyed() {
+        mSurfaceValid = false;
+        notifyAll();
+    }
+
+    synchronized void sizeChanged(int newWidth, int newHeight) {
+        mWidth = newWidth;
+        mHeight = newHeight;
+    }
+
+    private void initEGL() {
+        mEGL = (EGL10)EGLContext.getEGL();
+
+        mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+        if (mEGLDisplay == EGL10.EGL_NO_DISPLAY) {
+            throw new GLControllerException("eglGetDisplay() failed");
+        }
+
+        int[] version = new int[2];
+        if (!mEGL.eglInitialize(mEGLDisplay, version)) {
+            throw new GLControllerException("eglInitialize() failed");
+        }
+
+        mEGLConfig = chooseConfig();
+    }
+
+    private void initEGLContext() {
+        initEGL();
+
+        int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, mGLVersion, EGL10.EGL_NONE };
+        mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT,
+                attribList);
+        if (mEGLContext == null || mEGLContext == EGL10.EGL_NO_CONTEXT) {
+            throw new GLControllerException("createContext() failed");
+        }
+    }
+
+    private EGLConfig chooseConfig() {
+        int[] numConfigs = new int[1];
+        if (!mEGL.eglChooseConfig(mEGLDisplay, CONFIG_SPEC, null, 0, numConfigs) ||
+                numConfigs[0] <= 0) {
+            throw new GLControllerException("No available EGL configurations");
+        }
+
+        EGLConfig[] configs = new EGLConfig[numConfigs[0]];
+        if (!mEGL.eglChooseConfig(mEGLDisplay, CONFIG_SPEC, configs, numConfigs[0], numConfigs)) {
+            throw new GLControllerException("No EGL configuration for that specification");
+        }
+
+        // Select the first 565 RGB configuration.
+        int[] red = new int[1], green = new int[1], blue = new int[1];
+        for (EGLConfig config : configs) {
+            mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_RED_SIZE, red);
+            mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_GREEN_SIZE, green);
+            mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_BLUE_SIZE, blue);
+            if (red[0] == 5 && green[0] == 6 && blue[0] == 5) {
+                return config;

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list