[Libreoffice-commits] online.git: android/app android/.gitignore android/lib android/Makefile.am android/settings.gradle configure.ac .gitignore loleaflet/Makefile.am
Jan Holesovsky (via logerrit)
logerrit at kemper.freedesktop.org
Fri Jul 12 09:54:18 UTC 2019
.gitignore | 6
android/.gitignore | 20
android/Makefile.am | 12
android/app/.gitignore | 2
android/app/appSettings.gradle.in | 12
android/app/build.gradle | 172 ---
android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java | 503 ---------
android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java | 4
android/lib/.gitignore | 3
android/lib/build.gradle | 210 ++++
android/lib/libSettings.gradle.in | 11
android/lib/proguard-rules.pro | 21
android/lib/src/main/AndroidManifest.xml | 2
android/lib/src/main/cpp/androidapp.cpp | 20
android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java | 515 ++++++++++
android/lib/src/main/java/org/libreoffice/androidlib/PrintAdapter.java | 6
android/lib/src/main/java/org/libreoffice/androidlib/SlideShowActivity.java | 2
android/lib/src/main/res/layout/activity_main.xml | 2
android/lib/src/main/res/values/strings.xml | 8
android/settings.gradle | 2
configure.ac | 5
loleaflet/Makefile.am | 12
22 files changed, 821 insertions(+), 729 deletions(-)
New commits:
commit 2b13c69d75476bcc3a38bd0cd9798187e74ed4c4
Author: Jan Holesovsky <kendy at collabora.com>
AuthorDate: Thu Jul 11 11:29:13 2019 +0200
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Jul 12 11:52:56 2019 +0200
android: Split the actual editing Activity into an own library.
This way, it is more naturally visible what is the actuall app (with the
initial recent documents / file picker) and the editing part.
Change-Id: Ia764f2900939e980f703e3da9f9abd6c0aee7cbb
diff --git a/.gitignore b/.gitignore
index 52ee34543..eea283edd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,9 +95,9 @@ ios/Mobile/Assets.xcassets/AppIcon.appiconset
BUNDLE-VERSION
# android stuff
-/android/app/src/main/assets/dist
-/android/app/src/main/assets/hello-world.od*
-/android/app/src/main/cpp/CMakeLists.txt
+/android/lib/src/main/assets/dist
+/android/lib/src/main/assets/hello-world.od*
+/android/lib/src/main/cpp/CMakeLists.txt
# backup and temporary editor files: the only convenience rules allowed here.
*~
diff --git a/android/.gitignore b/android/.gitignore
index 6e50fa55a..9bdedd758 100644
--- a/android/.gitignore
+++ b/android/.gitignore
@@ -3,13 +3,13 @@
/android.iml
/gradle
/local.properties
-/app/src/main/assets/etc/
-/app/src/main/assets/example.odt
-/app/src/main/assets/license.txt
-/app/src/main/assets/license.html
-/app/src/main/assets/notice.txt
-/app/src/main/assets/program/
-/app/src/main/assets/share/
-/app/src/main/assets/unpack/
-/app/src/main/assets/user/
-/app/src/main/cpp/lib
+/lib/src/main/assets/etc/
+/lib/src/main/assets/example.odt
+/lib/src/main/assets/license.txt
+/lib/src/main/assets/license.html
+/lib/src/main/assets/notice.txt
+/lib/src/main/assets/program/
+/lib/src/main/assets/share/
+/lib/src/main/assets/unpack/
+/lib/src/main/assets/user/
+/lib/src/main/cpp/lib
diff --git a/android/Makefile.am b/android/Makefile.am
index 9d27873df..fb3076a46 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -1,12 +1,12 @@
clean-local:
- rm -rf $(abs_top_srcdir)/android/app/src/main/assets/*
+ rm -rf $(abs_top_srcdir)/android/lib/src/main/assets/*
rm -rf app/build
-all-local: app/src/main/assets/templates/untitled.odg \
- app/src/main/assets/templates/untitled.odp \
- app/src/main/assets/templates/untitled.ods \
- app/src/main/assets/templates/untitled.odt
+all-local: lib/src/main/assets/templates/untitled.odg \
+ lib/src/main/assets/templates/untitled.odp \
+ lib/src/main/assets/templates/untitled.ods \
+ lib/src/main/assets/templates/untitled.odt
-app/src/main/assets/templates/untitled.%: templates/untitled.%
+lib/src/main/assets/templates/untitled.%: templates/untitled.%
@mkdir -p $(dir $@)
@cp -a $< $@
diff --git a/android/app/.gitignore b/android/app/.gitignore
index 238a7c9a1..0e5159da5 100644
--- a/android/app/.gitignore
+++ b/android/app/.gitignore
@@ -1,4 +1,4 @@
/.externalNativeBuild
/app.iml
/build
-/liboSettings.gradle
+/appSettings.gradle
diff --git a/android/app/appSettings.gradle.in b/android/app/appSettings.gradle.in
new file mode 100644
index 000000000..d872ef2ea
--- /dev/null
+++ b/android/app/appSettings.gradle.in
@@ -0,0 +1,12 @@
+ext {
+ liboWorkdir = '@LOBUILDDIR@/workdir'
+ liboVersionMinor = '@LOOLWSD_VERSION_MAJOR@'
+ liboAppName = '@APP_NAME@'
+ liboVendor = '@VENDOR@'
+ liboInfoURL = '@INFO_URL@'
+}
+android.defaultConfig {
+ applicationId '@ANDROID_PACKAGE_NAME@'
+ versionCode 20
+ versionName '@LOOLWSD_VERSION@'
+}
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 0ee8baabe..aae9c4bc0 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'
// buildhost settings - paths and the like
-apply from: 'liboSettings.gradle'
+apply from: 'appSettings.gradle'
android {
compileSdkVersion 28
defaultConfig {
- // applicationId, versionCode and versionName are defined in liboSettings.gradle
+ // applicationId, versionCode and versionName are defined in appSettings.gradle
minSdkVersion 21
targetSdkVersion 28
}
@@ -36,17 +36,6 @@ android {
'proguard-rules.pro'
}
}
- sourceSets {
- main {
- // let gradle pack the shared library into apk
- jniLibs.srcDirs = ['src/main/cpp/lib']
- }
- }
- externalNativeBuild {
- cmake {
- path "src/main/cpp/CMakeLists.txt"
- }
- }
}
repositories {
@@ -65,160 +54,5 @@ dependencies {
//before changing the version please see https://issuetracker.google.com/issues/111662669
implementation 'androidx.preference:preference:1.1.0-alpha01'
+ implementation project(path: ':lib')
}
-
-task copyUnpackAssets(type: Copy) {
- description "copies assets that need to be extracted on the device"
- into 'src/main/assets/unpack'
- into('program') {
- from("${liboInstdir}/${liboEtcFolder}/types") {
- includes = [
- "offapi.rdb",
- "oovbaapi.rdb"
- ]
- }
- from("${liboInstdir}/${liboUreMiscFolder}") {
- includes = ["types.rdb"]
- rename 'types.rdb', 'udkapi.rdb'
- }
- }
- into('user/fonts') {
- from "${liboInstdir}/share/fonts/truetype"
- // Note: restrict list of fonts due to size considerations - no technical reason anymore
- // ToDo: fonts would be good candidate for using Expansion Files instead
- includes = [
- "Liberation*.ttf",
- "Caladea-*.ttf",
- "Carlito-*.ttf",
- "Gen*.ttf",
- "opens___.ttf"
- ]
- }
- into('etc/fonts') {
- from "${liboSrcRoot}/android/source/"
- includes = ['fonts.conf']
- filter {
- String line ->
- line.replaceAll(
- '@@APPLICATION_ID@@', new String("${android.defaultConfig.applicationId}")
- ).replaceAll(
- // FIXME Avoid the Android system fonts for the moment,
- // the huge Noto Sans fonts have terrible impact on the 1st
- // start performance.
- // The real solution would be to either make fontconfig
- // faster, or at least find a way to avoid only the Noto
- // Sans, or present a progressbar or something.
- // For the moment, we just copy the Roboto font (needed
- // for the dialogs; see MainActivity.copyFonts()) and
- // remove the system fonts from the config.
- '<dir>/system/fonts</dir>', new String("")
- )
- }
- }
-}
-
-task copyAssets(type: Copy) {
- description "copies assets that can be accessed within the installed apk"
- into 'src/main/assets'
- from("${liboSrcRoot}/instdir/") {
- includes = ["LICENSE.html", "NOTICE"]
- rename "LICENSE.html", "license.html"
- rename "NOTICE", "notice.txt"
- }
- from("${liboExampleDocument}") {
- rename ".*", "example.odt"
- }
- into('program') {
- from "${liboInstdir}/program"
- includes = ['services.rdb', 'services/services.rdb']
-
- into('resource') {
- from "${liboInstdir}/${liboSharedResFolder}"
- includes = ['*en-US.res']
- }
- }
- into('share') {
- from "${liboInstdir}/share"
- // Filter data is needed by e.g. the drawingML preset shape import.
- includes = ['registry/**', 'filter/**']
- }
-}
-
-task createFullConfig(type: Copy) {
- description "copies various configuration bits into the apk"
- into('src/main/assets/share/config')
- from("${liboInstdir}/share/config") {
- includes = ['soffice.cfg/**', 'images_colibre.zip']
- }
-}
-
-task createStrippedConfig {
- def preserveDir = file("src/main/assets/share/config/soffice.cfg/empty")
- outputs.dir "src/main/assets/share/registry/res"
- outputs.file preserveDir
-
- doLast {
- file('src/main/assets/share/registry/res').mkdirs()
- file("src/main/assets/share/config/soffice.cfg").mkdirs()
- // just empty file
- preserveDir.text = ""
- }
-}
-
-task createRCfiles {
- inputs.file "liboSettings.gradle"
- dependsOn copyUnpackAssets, copyAssets
- def sofficerc = file('src/main/assets/unpack/program/sofficerc')
- def fundamentalrc = file('src/main/assets/program/fundamentalrc')
- def bootstraprc = file('src/main/assets/program/bootstraprc')
- def unorc = file('src/main/assets/program/unorc')
- def versionrc = file('src/main/assets/program/versionrc')
-
- outputs.files sofficerc, fundamentalrc, unorc, bootstraprc, versionrc
-
- doLast {
- sofficerc.text = '''\
-[Bootstrap]
-Logo=1
-NativeProgress=1
-URE_BOOTSTRAP=file:///assets/program/fundamentalrc
-HOME=$APP_DATA_DIR/cache
-OSL_SOCKET_PATH=$APP_DATA_DIR/cache
-'''.stripIndent()
-
- fundamentalrc.text = '''\
-[Bootstrap]
-LO_LIB_DIR=file://$APP_DATA_DIR/lib/
-BRAND_BASE_DIR=file:///assets
-BRAND_SHARE_SUBDIR=share
-CONFIGURATION_LAYERS=xcsxcu:${BRAND_BASE_DIR}/share/registry res:${BRAND_BASE_DIR}/share/registry
-URE_BIN_DIR=file:///assets/ure/bin/dir/nothing-here/we-can/exec-anyway
-'''.stripIndent()
-
- bootstraprc.text = '''\
-[Bootstrap]
-InstallMode=<installmode>
-ProductKey=LibreOffice ''' + "${liboVersionMajor}.${liboVersionMinor}" + '''
-UserInstallation=file://$APP_DATA_DIR
-'''.stripIndent()
-
- unorc.text = '''\
-[Bootstrap]
-URE_INTERNAL_LIB_DIR=file://$APP_DATA_DIR/lib/
-UNO_TYPES=file://$APP_DATA_DIR/program/udkapi.rdb file://$APP_DATA_DIR/program/offapi.rdb file://$APP_DATA_DIR/program/oovbaapi.rdb
-UNO_SERVICES=file:///assets/program/services.rdb file:///assets/program/services/services.rdb
-'''.stripIndent()
-
- versionrc.text = '''\
-[Version]
-AllLanguages=en-US
-BuildVersion=
-buildid=''' + "${liboGitFullCommit}" + '''
-ReferenceOOoMajorMinor=4.1
-'''.stripIndent()
- }
-}
-
-// creating the UI stuff is cheap, don't bother only applying it for the flavor..
-preBuild.dependsOn 'createRCfiles',
- 'createFullConfig'
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java b/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java
index c2897e304..4c75b27c4 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java
+++ b/android/app/src/main/java/org/libreoffice/androidapp/MainActivity.java
@@ -9,508 +9,9 @@
package org.libreoffice.androidapp;
-import android.Manifest;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.print.PrintAttributes;
-import android.print.PrintDocumentAdapter;
-import android.print.PrintManager;
-import android.util.Log;
-import android.webkit.JavascriptInterface;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Toast;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.nio.channels.ReadableByteChannel;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-
-public class MainActivity extends AppCompatActivity {
- final static String TAG = "MainActivity";
-
- private static final String ASSETS_EXTRACTED_PREFS_KEY = "ASSETS_EXTRACTED";
- private static final int PERMISSION_READ_EXTERNAL_STORAGE = 777;
- private static final String KEY_ENABLE_SHOW_DEBUG_INFO = "ENABLE_SHOW_DEBUG_INFO";
-
- private static final String KEY_PROVIDER_ID = "providerID";
- private static final String KEY_DOCUMENT_URI = "documentUri";
- private static final String KEY_IS_EDITABLE = "isEditable";
- private static final String KEY_INTENT_URI = "intentUri";
-
- private File mTempFile = null;
-
- private int providerId;
-
- @Nullable
- private URI documentUri;
-
- private String urlToLoad;
- private WebView mWebView;
- private SharedPreferences sPrefs;
- private Handler mainHandler;
-
- private boolean isDocEditable = false;
- private boolean isDocDebuggable = BuildConfig.DEBUG;
-
- private static boolean copyFromAssets(AssetManager assetManager,
- String fromAssetPath, String targetDir) {
- try {
- String[] files = assetManager.list(fromAssetPath);
-
- boolean res = true;
- for (String file : files) {
- String[] dirOrFile = assetManager.list(fromAssetPath + "/" + file);
- if (dirOrFile.length == 0) {
- // noinspection ResultOfMethodCallIgnored
- new File(targetDir).mkdirs();
- res &= copyAsset(assetManager,
- fromAssetPath + "/" + file,
- targetDir + "/" + file);
- } else
- res &= copyFromAssets(assetManager,
- fromAssetPath + "/" + file,
- targetDir + "/" + file);
- }
- return res;
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(TAG, "copyFromAssets failed: " + e.getMessage());
- return false;
- }
- }
-
- private static boolean copyAsset(AssetManager assetManager, String fromAssetPath, String toPath) {
- ReadableByteChannel source = null;
- FileChannel dest = null;
- try {
- try {
- source = Channels.newChannel(assetManager.open(fromAssetPath));
- dest = new FileOutputStream(toPath).getChannel();
- long bytesTransferred = 0;
- // might not copy all at once, so make sure everything gets copied....
- ByteBuffer buffer = ByteBuffer.allocate(4096);
- while (source.read(buffer) > 0) {
- buffer.flip();
- bytesTransferred += dest.write(buffer);
- buffer.clear();
- }
- Log.v(TAG, "Success copying " + fromAssetPath + " to " + toPath + " bytes: " + bytesTransferred);
- return true;
- } finally {
- if (dest != null) dest.close();
- if (source != null) source.close();
- }
- } catch (FileNotFoundException e) {
- Log.e(TAG, "file " + fromAssetPath + " not found! " + e.getMessage());
- return false;
- } catch (IOException e) {
- Log.e(TAG, "failed to copy file " + fromAssetPath + " from assets to " + toPath + " - " + e.getMessage());
- return false;
- }
- }
-
- /** Copies fonts except the NotoSans from the system to our location.
- * This is necessary because the NotoSans is huge and fontconfig needs
- * ages to parse them.
- */
- private static boolean copyFonts(String fromPath, String targetDir) {
- try {
- File target = new File(targetDir);
- if (!target.exists())
- target.mkdirs();
-
- File from = new File(fromPath);
- File[] files = from.listFiles();
- for (File fontFile : files) {
- String fontFileName = fontFile.getName();
- if (!fontFileName.equals("Roboto-Regular.ttf")) {
- Log.i(TAG, "Ignored font file: " + fontFile);
- continue;
- }
- else {
- Log.i(TAG, "Copying font file: " + fontFile);
- }
-
- // copy the font file over
- InputStream in = new FileInputStream(fontFile);
- try {
- OutputStream out = new FileOutputStream(targetDir + "/" + fontFile.getName());
- try {
- byte[] buffer = new byte[4096];
- int len;
- while ((len = in.read(buffer)) > 0) {
- out.write(buffer, 0, len);
- }
- } finally {
- out.close();
- }
- } finally {
- in.close();
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(TAG, "copyFonts failed: " + e.getMessage());
- return false;
- }
-
- return true;
- }
-
- private void updatePreferences() {
- if (sPrefs.getInt(ASSETS_EXTRACTED_PREFS_KEY, 0) != BuildConfig.VERSION_CODE) {
- if (copyFromAssets(getAssets(), "unpack", getApplicationInfo().dataDir) &&
- copyFonts("/system/fonts", getApplicationInfo().dataDir + "/user/fonts")) {
- sPrefs.edit().putInt(ASSETS_EXTRACTED_PREFS_KEY, BuildConfig.VERSION_CODE).apply();
- }
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- sPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- updatePreferences();
-
- setContentView(R.layout.activity_main);
-
- AssetManager assetManager = getResources().getAssets();
-
- isDocDebuggable = sPrefs.getBoolean(KEY_ENABLE_SHOW_DEBUG_INFO, false) && BuildConfig.DEBUG;
-
- ApplicationInfo applicationInfo = getApplicationInfo();
- String dataDir = applicationInfo.dataDir;
- Log.i(TAG, String.format("Initializing LibreOfficeKit, dataDir=%s\n", dataDir));
-
- //redirectStdio(true);
-
- String cacheDir = getApplication().getCacheDir().getAbsolutePath();
- String apkFile = getApplication().getPackageResourcePath();
-
- if (getIntent().getData() != null) {
-
- if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
- isDocEditable = false;
- Toast.makeText(this, getResources().getString(R.string.temp_file_saving_disabled), Toast.LENGTH_SHORT).show();
- if (copyFileToTemp() && mTempFile != null) {
- documentUri = mTempFile.toURI();
- urlToLoad = documentUri.toString();
- Log.d(TAG, "SCHEME_CONTENT: getPath(): " + getIntent().getData().getPath());
- } else {
- // TODO: can't open the file
- Log.e(TAG, "couldn't create temporary file from " + getIntent().getData());
- }
- } else if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_FILE)) {
- isDocEditable = true;
- urlToLoad = getIntent().getData().getPath();
- Log.d(TAG, "SCHEME_FILE: getPath(): " + getIntent().getData().getPath());
- // Gather data to rebuild IFile object later
- providerId = getIntent().getIntExtra(
- "org.libreoffice.document_provider_id", 0);
- documentUri = (URI) getIntent().getSerializableExtra(
- "org.libreoffice.document_uri");
- }
- } else if (savedInstanceState != null) {
- getIntent().setAction(Intent.ACTION_VIEW)
- .setData(Uri.parse(savedInstanceState.getString(KEY_INTENT_URI)));
- urlToLoad = getIntent().getData().toString();
- providerId = savedInstanceState.getInt(KEY_PROVIDER_ID);
- if (savedInstanceState.getString(KEY_DOCUMENT_URI) != null) {
- try {
- documentUri = new URI(savedInstanceState.getString(KEY_DOCUMENT_URI));
- urlToLoad = documentUri.toString();
- } catch (URISyntaxException e) {
- e.printStackTrace();
- }
- }
- isDocEditable = savedInstanceState.getBoolean(KEY_IS_EDITABLE);
- } else {
- //User can't reach here but if he/she does then
- Toast.makeText(this, getString(R.string.failed_to_load_file), Toast.LENGTH_SHORT).show();
- finish();
- }
-
- createLOOLWSD(dataDir, cacheDir, apkFile, assetManager, urlToLoad);
-
- mWebView = findViewById(R.id.browser);
- mWebView.setWebViewClient(new WebViewClient());
-
- WebSettings webSettings = mWebView.getSettings();
- webSettings.setJavaScriptEnabled(true);
- mWebView.addJavascriptInterface(this, "LOOLMessageHandler");
-
- // allow debugging (when building the debug version); see details in
- // https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- WebView.setWebContentsDebuggingEnabled(true);
- }
- }
- mainHandler = new Handler(getMainLooper());
- }
-
-
- @Override
- protected void onStart() {
- super.onStart();
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- Log.i(TAG, "asking for read storage permission");
- ActivityCompat.requestPermissions(this,
- new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
- PERMISSION_READ_EXTERNAL_STORAGE);
- } else {
- loadDocument();
- }
- }
-
- @Override
- protected void onSaveInstanceState(@NonNull Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putString(KEY_INTENT_URI, getIntent().getData().toString());
- outState.putInt(KEY_PROVIDER_ID, providerId);
- if (documentUri != null) {
- outState.putString(KEY_DOCUMENT_URI, documentUri.toString());
- }
- //If this activity was opened via contentUri
- outState.putBoolean(KEY_IS_EDITABLE, isDocEditable);
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- switch (requestCode) {
- case PERMISSION_READ_EXTERNAL_STORAGE:
- if (permissions.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- loadDocument();
- } else {
- Toast.makeText(this, getString(R.string.storage_permission_required), Toast.LENGTH_SHORT).show();
- finish();
- break;
- }
- break;
- default:
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }
- }
-
- private boolean copyFileToTemp() {
- ContentResolver contentResolver = getContentResolver();
- FileChannel inputChannel = null;
- FileChannel outputChannel = null;
- // CSV files need a .csv suffix to be opened in Calc.
- String suffix = null;
- String intentType = getIntent().getType();
- // K-9 mail uses the first, GMail uses the second variant.
- if ("text/comma-separated-values".equals(intentType) || "text/csv".equals(intentType))
- suffix = ".csv";
-
- try {
- try {
- AssetFileDescriptor assetFD = contentResolver.openAssetFileDescriptor(getIntent().getData(), "r");
- if (assetFD == null) {
- Log.e(TAG, "couldn't create assetfiledescriptor from " + getIntent().getDataString());
- return false;
- }
- inputChannel = assetFD.createInputStream().getChannel();
- mTempFile = File.createTempFile("LibreOffice", suffix, this.getCacheDir());
-
- outputChannel = new FileOutputStream(mTempFile).getChannel();
- long bytesTransferred = 0;
- // might not copy all at once, so make sure everything gets copied....
- while (bytesTransferred < inputChannel.size()) {
- bytesTransferred += outputChannel.transferFrom(inputChannel, bytesTransferred, inputChannel.size());
- }
- Log.e(TAG, "Success copying " + bytesTransferred + " bytes");
- return true;
- } finally {
- if (inputChannel != null) inputChannel.close();
- if (outputChannel != null) outputChannel.close();
- }
- } catch (FileNotFoundException e) {
- return false;
- } catch (IOException e) {
- return false;
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Log.i(TAG, "onResume..");
-
- // check for config change
- updatePreferences();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- Log.d(TAG, "onPause() - unload the document");
- postMobileMessageNative("BYE");
- }
-
- private void loadDocument() {
- String finalUrlToLoad = "file:///android_asset/dist/loleaflet.html?file_path=" +
- urlToLoad + "&closebutton=1";
- if (isDocEditable) {
- finalUrlToLoad += "&permission=edit";
- } else {
- finalUrlToLoad += "&permission=readonly";
- }
- if (isDocDebuggable) {
- finalUrlToLoad += "&debug=true";
- }
- mWebView.loadUrl(finalUrlToLoad);
- }
-
- static {
- System.loadLibrary("androidapp");
- }
-
- /**
- * Initialize the LOOLWSD to load 'loadFileURL'.
- */
- public native void createLOOLWSD(String dataDir, String cacheDir, String apkFile, AssetManager assetManager, String loadFileURL);
-
- /**
- * Passing messages from JS (instead of the websocket communication).
- */
- @JavascriptInterface
- public void postMobileMessage(String message) {
- Log.d(TAG, "postMobileMessage: " + message);
-
- if (interceptMsgFromWebView(message)) {
- postMobileMessageNative(message);
- }
-
- // Going back to document browser on BYE (called when pressing the top left exit button)
- if (message.equals("BYE"))
- finish();
- }
-
- /**
- * Call the post method form C++
- */
- public native void postMobileMessageNative(String message);
-
- /**
- * Passing messages from JS (instead of the websocket communication).
- */
- @JavascriptInterface
- public void postMobileError(String message) {
- // TODO handle this
- Log.d(TAG, "postMobileError: " + message);
- }
-
- /**
- * Passing messages from JS (instead of the websocket communication).
- */
- @JavascriptInterface
- public void postMobileDebug(String message) {
- // TODO handle this
- Log.d(TAG, "postMobileDebug: " + message);
- }
-
- /**
- * Passing message the other way around - from Java to the FakeWebSocket in JS.
- */
- void callFakeWebsocketOnMessage(final String message) {
- // call from the UI thread
- mWebView.post(new Runnable() {
- public void run() {
- Log.i(TAG, "Forwarding to the WebView: " + message);
- mWebView.loadUrl("javascript:window.TheFakeWebSocket.onmessage({'data':" + message + "});");
- }
- });
- }
-
- /**
- * return true to pass the message to the native part and false to block the message
- */
- boolean interceptMsgFromWebView(String message) {
- if (message.equals("PRINT")) {
- mainHandler.post(new Runnable() {
- @Override
- public void run() {
- initiatePrint();
- }
- });
- return false;
- } else if (message.equals("SLIDESHOW")) {
- initiateSlideShow();
- return false;
- }
- return true;
- }
-
- private void initiatePrint() {
- PrintManager printManager = (PrintManager) getSystemService(PRINT_SERVICE);
- PrintDocumentAdapter printAdapter = new PrintAdapter(MainActivity.this);
- printManager.print("Document", printAdapter, new PrintAttributes.Builder().build());
- }
-
- private void initiateSlideShow() {
- final AlertDialog slideShowProgress = new AlertDialog.Builder(this)
- .setCancelable(false)
- .setView(R.layout.dialog_loading)
- .create();
- new AsyncTask<Void, Void, String>() {
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- slideShowProgress.show();
- }
-
- @Override
- protected String doInBackground(Void... voids) {
- Log.v(TAG, "saving svg for slideshow by " + Thread.currentThread().getName());
- String slideShowFileUri = new File(getCacheDir(), "slideShow.svg").toURI().toString();
- saveAs(slideShowFileUri, "svg");
- return slideShowFileUri;
- }
-
- @Override
- protected void onPostExecute(String slideShowFileUri) {
- super.onPostExecute(slideShowFileUri);
- slideShowProgress.dismiss();
- Intent slideShowActIntent = new Intent(MainActivity.this, SlideShowActivity.class);
- slideShowActIntent.putExtra(SlideShowActivity.SVG_URI_KEY, slideShowFileUri);
- startActivity(slideShowActIntent);
- }
- }.execute();
- }
-
- public native void saveAs(String fileUri, String format);
+import org.libreoffice.androidlib.LOActivity;
+public class MainActivity extends LOActivity {
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java b/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java
index cc0bb1bc9..9e3f87e22 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java
+++ b/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java
@@ -32,7 +32,6 @@ import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.Editable;
-import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
@@ -70,11 +69,8 @@ import org.libreoffice.androidapp.storage.DocumentProviderSettingsActivity;
import org.libreoffice.androidapp.storage.IDocumentProvider;
import org.libreoffice.androidapp.storage.IFile;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
diff --git a/android/lib/.gitignore b/android/lib/.gitignore
new file mode 100644
index 000000000..77eda0d14
--- /dev/null
+++ b/android/lib/.gitignore
@@ -0,0 +1,3 @@
+/build
+/lib.iml
+/libSettings.gradle
diff --git a/android/lib/build.gradle b/android/lib/build.gradle
new file mode 100644
index 000000000..f208d302b
--- /dev/null
+++ b/android/lib/build.gradle
@@ -0,0 +1,210 @@
+apply plugin: 'com.android.library'
+
+// buildhost settings - paths and the like
+apply from: 'libSettings.gradle'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ debug {
+ ndk {
+ //abiFilters "x86", "armeabi-v7a", "armeabi"
+ abiFilters "armeabi-v7a"
+ }
+ debuggable true
+ }
+ release {
+ ndk {
+ abiFilters "armeabi-v7a"
+ }
+ minifyEnabled false // FIXME disabled before we get a good proguardRules for callFakeWebsocketOnMessage calling from C++
+ shrinkResources false // FIXME cannot be enabled when minifyEnabled is turned off
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ sourceSets {
+ main {
+ // let gradle pack the shared library into apk
+ jniLibs.srcDirs = ['src/main/cpp/lib']
+ }
+ }
+
+ externalNativeBuild {
+ cmake {
+ path "src/main/cpp/CMakeLists.txt"
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'androidx.appcompat:appcompat:1.0.2'
+ implementation 'com.google.android.material:material:1.1.0-alpha04'
+}
+
+task copyUnpackAssets(type: Copy) {
+ description "copies assets that need to be extracted on the device"
+ into 'src/main/assets/unpack'
+ into('program') {
+ from("${liboInstdir}/${liboEtcFolder}/types") {
+ includes = [
+ "offapi.rdb",
+ "oovbaapi.rdb"
+ ]
+ }
+ from("${liboInstdir}/${liboUreMiscFolder}") {
+ includes = ["types.rdb"]
+ rename 'types.rdb', 'udkapi.rdb'
+ }
+ }
+ into('user/fonts') {
+ from "${liboInstdir}/share/fonts/truetype"
+ // Note: restrict list of fonts due to size considerations - no technical reason anymore
+ // ToDo: fonts would be good candidate for using Expansion Files instead
+ includes = [
+ "Liberation*.ttf",
+ "Caladea-*.ttf",
+ "Carlito-*.ttf",
+ "Gen*.ttf",
+ "opens___.ttf"
+ ]
+ }
+ into('etc/fonts') {
+ from "${liboSrcRoot}/android/source/"
+ includes = ['fonts.conf']
+ filter {
+ String line ->
+ line.replaceAll(
+ '@@APPLICATION_ID@@', new String("${android.defaultConfig.applicationId}")
+ ).replaceAll(
+ // FIXME Avoid the Android system fonts for the moment,
+ // the huge Noto Sans fonts have terrible impact on the 1st
+ // start performance.
+ // The real solution would be to either make fontconfig
+ // faster, or at least find a way to avoid only the Noto
+ // Sans, or present a progressbar or something.
+ // For the moment, we just copy the Roboto font (needed
+ // for the dialogs; see LOActivity.copyFonts()) and
+ // remove the system fonts from the config.
+ '<dir>/system/fonts</dir>', new String("")
+ )
+ }
+ }
+}
+
+task copyAssets(type: Copy) {
+ description "copies assets that can be accessed within the installed apk"
+ into 'src/main/assets'
+ from("${liboSrcRoot}/instdir/") {
+ includes = ["LICENSE.html", "NOTICE"]
+ rename "LICENSE.html", "license.html"
+ rename "NOTICE", "notice.txt"
+ }
+ from("${liboExampleDocument}") {
+ rename ".*", "example.odt"
+ }
+ into('program') {
+ from "${liboInstdir}/program"
+ includes = ['services.rdb', 'services/services.rdb']
+
+ into('resource') {
+ from "${liboInstdir}/${liboSharedResFolder}"
+ includes = ['*en-US.res']
+ }
+ }
+ into('share') {
+ from "${liboInstdir}/share"
+ // Filter data is needed by e.g. the drawingML preset shape import.
+ includes = ['registry/**', 'filter/**']
+ }
+}
+
+task createFullConfig(type: Copy) {
+ description "copies various configuration bits into the apk"
+ into('src/main/assets/share/config')
+ from("${liboInstdir}/share/config") {
+ includes = ['soffice.cfg/**', 'images_colibre.zip']
+ }
+}
+
+task createStrippedConfig {
+ def preserveDir = file("src/main/assets/share/config/soffice.cfg/empty")
+ outputs.dir "src/main/assets/share/registry/res"
+ outputs.file preserveDir
+
+ doLast {
+ file('src/main/assets/share/registry/res').mkdirs()
+ file("src/main/assets/share/config/soffice.cfg").mkdirs()
+ // just empty file
+ preserveDir.text = ""
+ }
+}
+
+task createRCfiles {
+ inputs.file "libSettings.gradle"
+ dependsOn copyUnpackAssets, copyAssets
+ def sofficerc = file('src/main/assets/unpack/program/sofficerc')
+ def fundamentalrc = file('src/main/assets/program/fundamentalrc')
+ def bootstraprc = file('src/main/assets/program/bootstraprc')
+ def unorc = file('src/main/assets/program/unorc')
+ def versionrc = file('src/main/assets/program/versionrc')
+
+ outputs.files sofficerc, fundamentalrc, unorc, bootstraprc, versionrc
+
+ doLast {
+ sofficerc.text = '''\
+[Bootstrap]
+Logo=1
+NativeProgress=1
+URE_BOOTSTRAP=file:///assets/program/fundamentalrc
+HOME=$APP_DATA_DIR/cache
+OSL_SOCKET_PATH=$APP_DATA_DIR/cache
+'''.stripIndent()
+
+ fundamentalrc.text = '''\
+[Bootstrap]
+LO_LIB_DIR=file://$APP_DATA_DIR/lib/
+BRAND_BASE_DIR=file:///assets
+BRAND_SHARE_SUBDIR=share
+CONFIGURATION_LAYERS=xcsxcu:${BRAND_BASE_DIR}/share/registry res:${BRAND_BASE_DIR}/share/registry
+URE_BIN_DIR=file:///assets/ure/bin/dir/nothing-here/we-can/exec-anyway
+'''.stripIndent()
+
+ bootstraprc.text = '''\
+[Bootstrap]
+InstallMode=<installmode>
+ProductKey=LibreOffice ''' + "${liboVersionMajor}.${liboVersionMinor}" + '''
+UserInstallation=file://$APP_DATA_DIR
+'''.stripIndent()
+
+ unorc.text = '''\
+[Bootstrap]
+URE_INTERNAL_LIB_DIR=file://$APP_DATA_DIR/lib/
+UNO_TYPES=file://$APP_DATA_DIR/program/udkapi.rdb file://$APP_DATA_DIR/program/offapi.rdb file://$APP_DATA_DIR/program/oovbaapi.rdb
+UNO_SERVICES=file:///assets/program/services.rdb file:///assets/program/services/services.rdb
+'''.stripIndent()
+
+ versionrc.text = '''\
+[Version]
+AllLanguages=en-US
+BuildVersion=
+buildid=''' + "${liboGitFullCommit}" + '''
+ReferenceOOoMajorMinor=4.1
+'''.stripIndent()
+ }
+}
+
+// creating the UI stuff is cheap, don't bother only applying it for the flavor..
+preBuild.dependsOn 'createRCfiles',
+ 'createFullConfig'
diff --git a/android/app/liboSettings.gradle.in b/android/lib/libSettings.gradle.in
similarity index 54%
rename from android/app/liboSettings.gradle.in
rename to android/lib/libSettings.gradle.in
index 80234582b..3736a35fe 100644
--- a/android/app/liboSettings.gradle.in
+++ b/android/lib/libSettings.gradle.in
@@ -1,22 +1,11 @@
ext {
liboSrcRoot = '@LOBUILDDIR@'
- liboWorkdir = '@LOBUILDDIR@/workdir'
liboInstdir = '@LOBUILDDIR@/instdir'
liboEtcFolder = 'program'
liboUreMiscFolder = 'program'
liboSharedResFolder = 'program/resource'
- liboUREJavaFolder = 'program/classes'
- liboShareJavaFolder = 'program/classes'
liboExampleDocument = '@LOBUILDDIR@/android/default-document/example.odt'
liboVersionMajor = '@LOOLWSD_VERSION_MAJOR@'
liboVersionMinor = '@LOOLWSD_VERSION_MAJOR@'
liboGitFullCommit = '@LOOLWSD_VERSION_HASH@'
- liboAppName = '@APP_NAME@'
- liboVendor = '@VENDOR@'
- liboInfoURL = '@INFO_URL@'
-}
-android.defaultConfig {
- applicationId '@ANDROID_PACKAGE_NAME@'
- versionCode 1
- versionName '@LOOLWSD_VERSION@'
}
diff --git a/android/lib/proguard-rules.pro b/android/lib/proguard-rules.pro
new file mode 100644
index 000000000..f1b424510
--- /dev/null
+++ b/android/lib/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/android/lib/src/main/AndroidManifest.xml b/android/lib/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..4738b240d
--- /dev/null
+++ b/android/lib/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.libreoffice.androidlib" />
diff --git a/android/app/src/main/cpp/CMakeLists.txt.in b/android/lib/src/main/cpp/CMakeLists.txt.in
similarity index 100%
rename from android/app/src/main/cpp/CMakeLists.txt.in
rename to android/lib/src/main/cpp/CMakeLists.txt.in
diff --git a/android/app/src/main/cpp/androidapp.cpp b/android/lib/src/main/cpp/androidapp.cpp
similarity index 92%
rename from android/app/src/main/cpp/androidapp.cpp
rename to android/lib/src/main/cpp/androidapp.cpp
index 7f5cf0f74..54541e7c4 100644
--- a/android/app/src/main/cpp/androidapp.cpp
+++ b/android/lib/src/main/cpp/androidapp.cpp
@@ -55,7 +55,7 @@ JNI_OnLoad(JavaVM* vm, void*) {
return JNI_VERSION_1_6;
}
-static void send2JS(jclass mainActivityClz, jobject mainActivityObj, const std::vector<char>& buffer)
+static void send2JS(jclass loActivityClz, jobject loActivityObj, const std::vector<char>& buffer)
{
LOG_DBG("Send to JS: " << LOOLProtocol::getAbbreviatedMessage(buffer.data(), buffer.size()));
@@ -133,8 +133,8 @@ static void send2JS(jclass mainActivityClz, jobject mainActivityObj, const std::
}
jstring jstr = env->NewStringUTF(js.c_str());
- jmethodID callFakeWebsocket = env->GetMethodID(mainActivityClz, "callFakeWebsocketOnMessage", "(Ljava/lang/String;)V");
- env->CallVoidMethod(mainActivityObj, callFakeWebsocket, jstr);
+ jmethodID callFakeWebsocket = env->GetMethodID(loActivityClz, "callFakeWebsocketOnMessage", "(Ljava/lang/String;)V");
+ env->CallVoidMethod(loActivityObj, callFakeWebsocket, jstr);
if (env->ExceptionCheck())
env->ExceptionDescribe();
@@ -144,7 +144,7 @@ static void send2JS(jclass mainActivityClz, jobject mainActivityObj, const std::
/// Handle a message from JavaScript.
extern "C" JNIEXPORT void JNICALL
-Java_org_libreoffice_androidapp_MainActivity_postMobileMessageNative(JNIEnv *env, jobject instance, jstring message)
+Java_org_libreoffice_androidlib_LOActivity_postMobileMessageNative(JNIEnv *env, jobject instance, jstring message)
{
const char *string_value = env->GetStringUTFChars(message, nullptr);
@@ -172,10 +172,10 @@ Java_org_libreoffice_androidapp_MainActivity_postMobileMessageNative(JNIEnv *env
// Start another thread to read responses and forward them to the JavaScript
jclass clz = env->GetObjectClass(instance);
- jclass mainActivityClz = (jclass) env->NewGlobalRef(clz);
- jobject mainActivityObj = env->NewGlobalRef(instance);
+ jclass loActivityClz = (jclass) env->NewGlobalRef(clz);
+ jobject loActivityObj = env->NewGlobalRef(instance);
- std::thread([mainActivityClz, mainActivityObj, currentFakeClientFd]
+ std::thread([loActivityClz, loActivityObj, currentFakeClientFd]
{
Util::setThreadName("app2js");
while (true)
@@ -215,7 +215,7 @@ Java_org_libreoffice_androidapp_MainActivity_postMobileMessageNative(JNIEnv *env
return;
std::vector<char> buf(n);
n = fakeSocketRead(currentFakeClientFd, buf.data(), n);
- send2JS(mainActivityClz, mainActivityObj, buf);
+ send2JS(loActivityClz, loActivityObj, buf);
}
}
else
@@ -268,7 +268,7 @@ extern "C" jboolean libreofficekit_initialize(JNIEnv* env, jstring dataDir, jstr
/// Create the LOOLWSD instance.
extern "C" JNIEXPORT void JNICALL
-Java_org_libreoffice_androidapp_MainActivity_createLOOLWSD(JNIEnv *env, jobject, jstring dataDir, jstring cacheDir, jstring apkFile, jobject assetManager, jstring loadFileURL)
+Java_org_libreoffice_androidlib_LOActivity_createLOOLWSD(JNIEnv *env, jobject, jstring dataDir, jstring cacheDir, jstring apkFile, jobject assetManager, jstring loadFileURL)
{
fileURL = std::string(env->GetStringUTFChars(loadFileURL, nullptr));
@@ -309,7 +309,7 @@ Java_org_libreoffice_androidapp_MainActivity_createLOOLWSD(JNIEnv *env, jobject,
extern "C"
JNIEXPORT void JNICALL
-Java_org_libreoffice_androidapp_MainActivity_saveAs(JNIEnv *env, jobject instance,
+Java_org_libreoffice_androidlib_LOActivity_saveAs(JNIEnv *env, jobject instance,
jstring fileUri_, jstring format_) {
const char *fileUri = env->GetStringUTFChars(fileUri_, 0);
const char *format = env->GetStringUTFChars(format_, 0);
diff --git a/android/app/src/main/cpp/androidapp.hpp b/android/lib/src/main/cpp/androidapp.hpp
similarity index 100%
rename from android/app/src/main/cpp/androidapp.hpp
rename to android/lib/src/main/cpp/androidapp.hpp
diff --git a/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java b/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java
new file mode 100644
index 000000000..861c114c4
--- /dev/null
+++ b/android/lib/src/main/java/org/libreoffice/androidlib/LOActivity.java
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package org.libreoffice.androidlib;
+
+import android.Manifest;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintManager;
+import android.util.Log;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+
+public class LOActivity extends AppCompatActivity {
+ final static String TAG = "LOActivity";
+
+ private static final String ASSETS_EXTRACTED_PREFS_KEY = "ASSETS_EXTRACTED";
+ private static final int PERMISSION_READ_EXTERNAL_STORAGE = 777;
+ private static final String KEY_ENABLE_SHOW_DEBUG_INFO = "ENABLE_SHOW_DEBUG_INFO";
+
+ private static final String KEY_PROVIDER_ID = "providerID";
+ private static final String KEY_DOCUMENT_URI = "documentUri";
+ private static final String KEY_IS_EDITABLE = "isEditable";
+ private static final String KEY_INTENT_URI = "intentUri";
+
+ private File mTempFile = null;
+
+ private int providerId;
+
+ @Nullable
+ private URI documentUri;
+
+ private String urlToLoad;
+ private WebView mWebView;
+ private SharedPreferences sPrefs;
+ private Handler mainHandler;
+
+ private boolean isDocEditable = false;
+ private boolean isDocDebuggable = BuildConfig.DEBUG;
+
+ private static boolean copyFromAssets(AssetManager assetManager,
+ String fromAssetPath, String targetDir) {
+ try {
+ String[] files = assetManager.list(fromAssetPath);
+
+ boolean res = true;
+ for (String file : files) {
+ String[] dirOrFile = assetManager.list(fromAssetPath + "/" + file);
+ if (dirOrFile.length == 0) {
+ // noinspection ResultOfMethodCallIgnored
+ new File(targetDir).mkdirs();
+ res &= copyAsset(assetManager,
+ fromAssetPath + "/" + file,
+ targetDir + "/" + file);
+ } else
+ res &= copyFromAssets(assetManager,
+ fromAssetPath + "/" + file,
+ targetDir + "/" + file);
+ }
+ return res;
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "copyFromAssets failed: " + e.getMessage());
+ return false;
+ }
+ }
+
+ private static boolean copyAsset(AssetManager assetManager, String fromAssetPath, String toPath) {
+ ReadableByteChannel source = null;
+ FileChannel dest = null;
+ try {
+ try {
+ source = Channels.newChannel(assetManager.open(fromAssetPath));
+ dest = new FileOutputStream(toPath).getChannel();
+ long bytesTransferred = 0;
+ // might not copy all at once, so make sure everything gets copied....
+ ByteBuffer buffer = ByteBuffer.allocate(4096);
+ while (source.read(buffer) > 0) {
+ buffer.flip();
+ bytesTransferred += dest.write(buffer);
+ buffer.clear();
+ }
+ Log.v(TAG, "Success copying " + fromAssetPath + " to " + toPath + " bytes: " + bytesTransferred);
+ return true;
+ } finally {
+ if (dest != null) dest.close();
+ if (source != null) source.close();
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "file " + fromAssetPath + " not found! " + e.getMessage());
+ return false;
+ } catch (IOException e) {
+ Log.e(TAG, "failed to copy file " + fromAssetPath + " from assets to " + toPath + " - " + e.getMessage());
+ return false;
+ }
+ }
+
+ /** Copies fonts except the NotoSans from the system to our location.
+ * This is necessary because the NotoSans is huge and fontconfig needs
+ * ages to parse them.
+ */
+ private static boolean copyFonts(String fromPath, String targetDir) {
+ try {
+ File target = new File(targetDir);
+ if (!target.exists())
+ target.mkdirs();
+
+ File from = new File(fromPath);
+ File[] files = from.listFiles();
+ for (File fontFile : files) {
+ String fontFileName = fontFile.getName();
+ if (!fontFileName.equals("Roboto-Regular.ttf")) {
+ Log.i(TAG, "Ignored font file: " + fontFile);
+ continue;
+ }
+ else {
+ Log.i(TAG, "Copying font file: " + fontFile);
+ }
+
+ // copy the font file over
+ InputStream in = new FileInputStream(fontFile);
+ try {
+ OutputStream out = new FileOutputStream(targetDir + "/" + fontFile.getName());
+ try {
+ byte[] buffer = new byte[4096];
+ int len;
+ while ((len = in.read(buffer)) > 0) {
+ out.write(buffer, 0, len);
+ }
+ } finally {
+ out.close();
+ }
+ } finally {
+ in.close();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "copyFonts failed: " + e.getMessage());
+ return false;
+ }
+
+ return true;
+ }
+
+ private void updatePreferences() {
+ if (sPrefs.getInt(ASSETS_EXTRACTED_PREFS_KEY, 0) != BuildConfig.VERSION_CODE) {
+ if (copyFromAssets(getAssets(), "unpack", getApplicationInfo().dataDir) &&
+ copyFonts("/system/fonts", getApplicationInfo().dataDir + "/user/fonts")) {
+ sPrefs.edit().putInt(ASSETS_EXTRACTED_PREFS_KEY, BuildConfig.VERSION_CODE).apply();
+ }
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ sPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ updatePreferences();
+
+ setContentView(R.layout.activity_main);
+
+ AssetManager assetManager = getResources().getAssets();
+
+ isDocDebuggable = sPrefs.getBoolean(KEY_ENABLE_SHOW_DEBUG_INFO, false) && BuildConfig.DEBUG;
+
+ ApplicationInfo applicationInfo = getApplicationInfo();
+ String dataDir = applicationInfo.dataDir;
+ Log.i(TAG, String.format("Initializing LibreOfficeKit, dataDir=%s\n", dataDir));
+
+ //redirectStdio(true);
+
+ String cacheDir = getApplication().getCacheDir().getAbsolutePath();
+ String apkFile = getApplication().getPackageResourcePath();
+
+ if (getIntent().getData() != null) {
+
+ if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
+ isDocEditable = false;
+ Toast.makeText(this, getResources().getString(R.string.temp_file_saving_disabled), Toast.LENGTH_SHORT).show();
+ if (copyFileToTemp() && mTempFile != null) {
+ documentUri = mTempFile.toURI();
+ urlToLoad = documentUri.toString();
+ Log.d(TAG, "SCHEME_CONTENT: getPath(): " + getIntent().getData().getPath());
+ } else {
+ // TODO: can't open the file
+ Log.e(TAG, "couldn't create temporary file from " + getIntent().getData());
+ }
+ } else if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_FILE)) {
+ isDocEditable = true;
+ urlToLoad = getIntent().getData().getPath();
+ Log.d(TAG, "SCHEME_FILE: getPath(): " + getIntent().getData().getPath());
+ // Gather data to rebuild IFile object later
+ providerId = getIntent().getIntExtra(
+ "org.libreoffice.document_provider_id", 0);
+ documentUri = (URI) getIntent().getSerializableExtra(
+ "org.libreoffice.document_uri");
+ }
+ } else if (savedInstanceState != null) {
+ getIntent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse(savedInstanceState.getString(KEY_INTENT_URI)));
+ urlToLoad = getIntent().getData().toString();
+ providerId = savedInstanceState.getInt(KEY_PROVIDER_ID);
+ if (savedInstanceState.getString(KEY_DOCUMENT_URI) != null) {
+ try {
+ documentUri = new URI(savedInstanceState.getString(KEY_DOCUMENT_URI));
+ urlToLoad = documentUri.toString();
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ }
+ isDocEditable = savedInstanceState.getBoolean(KEY_IS_EDITABLE);
+ } else {
+ //User can't reach here but if he/she does then
+ Toast.makeText(this, getString(R.string.failed_to_load_file), Toast.LENGTH_SHORT).show();
+ finish();
+ }
+
+ createLOOLWSD(dataDir, cacheDir, apkFile, assetManager, urlToLoad);
+
+ mWebView = findViewById(R.id.browser);
+ mWebView.setWebViewClient(new WebViewClient());
+
+ WebSettings webSettings = mWebView.getSettings();
+ webSettings.setJavaScriptEnabled(true);
+ mWebView.addJavascriptInterface(this, "LOOLMessageHandler");
+
+ // allow debugging (when building the debug version); see details in
+ // https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ WebView.setWebContentsDebuggingEnabled(true);
+ }
+ }
+ mainHandler = new Handler(getMainLooper());
+ }
+
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ Log.i(TAG, "asking for read storage permission");
+ ActivityCompat.requestPermissions(this,
+ new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+ PERMISSION_READ_EXTERNAL_STORAGE);
+ } else {
+ loadDocument();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(KEY_INTENT_URI, getIntent().getData().toString());
+ outState.putInt(KEY_PROVIDER_ID, providerId);
+ if (documentUri != null) {
+ outState.putString(KEY_DOCUMENT_URI, documentUri.toString());
+ }
+ //If this activity was opened via contentUri
+ outState.putBoolean(KEY_IS_EDITABLE, isDocEditable);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case PERMISSION_READ_EXTERNAL_STORAGE:
+ if (permissions.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ loadDocument();
+ } else {
+ Toast.makeText(this, getString(R.string.storage_permission_required), Toast.LENGTH_SHORT).show();
+ finish();
+ break;
+ }
+ break;
+ default:
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ }
+
+ private boolean copyFileToTemp() {
+ ContentResolver contentResolver = getContentResolver();
+ FileChannel inputChannel = null;
+ FileChannel outputChannel = null;
+ // CSV files need a .csv suffix to be opened in Calc.
+ String suffix = null;
+ String intentType = getIntent().getType();
+ // K-9 mail uses the first, GMail uses the second variant.
+ if ("text/comma-separated-values".equals(intentType) || "text/csv".equals(intentType))
+ suffix = ".csv";
+
+ try {
+ try {
+ AssetFileDescriptor assetFD = contentResolver.openAssetFileDescriptor(getIntent().getData(), "r");
+ if (assetFD == null) {
+ Log.e(TAG, "couldn't create assetfiledescriptor from " + getIntent().getDataString());
+ return false;
+ }
+ inputChannel = assetFD.createInputStream().getChannel();
+ mTempFile = File.createTempFile("LibreOffice", suffix, this.getCacheDir());
+
+ outputChannel = new FileOutputStream(mTempFile).getChannel();
+ long bytesTransferred = 0;
+ // might not copy all at once, so make sure everything gets copied....
+ while (bytesTransferred < inputChannel.size()) {
+ bytesTransferred += outputChannel.transferFrom(inputChannel, bytesTransferred, inputChannel.size());
+ }
+ Log.e(TAG, "Success copying " + bytesTransferred + " bytes");
+ return true;
+ } finally {
+ if (inputChannel != null) inputChannel.close();
+ if (outputChannel != null) outputChannel.close();
+ }
+ } catch (FileNotFoundException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ Log.i(TAG, "onResume..");
+
+ // check for config change
+ updatePreferences();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ Log.d(TAG, "onPause() - unload the document");
+ postMobileMessageNative("BYE");
+ }
+
+ private void loadDocument() {
+ String finalUrlToLoad = "file:///android_asset/dist/loleaflet.html?file_path=" +
+ urlToLoad + "&closebutton=1";
+ if (isDocEditable) {
+ finalUrlToLoad += "&permission=edit";
+ } else {
+ finalUrlToLoad += "&permission=readonly";
+ }
+ if (isDocDebuggable) {
+ finalUrlToLoad += "&debug=true";
+ }
+ mWebView.loadUrl(finalUrlToLoad);
+ }
+
+ static {
+ System.loadLibrary("androidapp");
+ }
+
+ /**
+ * Initialize the LOOLWSD to load 'loadFileURL'.
+ */
+ public native void createLOOLWSD(String dataDir, String cacheDir, String apkFile, AssetManager assetManager, String loadFileURL);
+
+ /**
+ * Passing messages from JS (instead of the websocket communication).
+ */
+ @JavascriptInterface
+ public void postMobileMessage(String message) {
+ Log.d(TAG, "postMobileMessage: " + message);
+
+ if (interceptMsgFromWebView(message)) {
+ postMobileMessageNative(message);
+ }
+
+ // Going back to document browser on BYE (called when pressing the top left exit button)
+ if (message.equals("BYE"))
+ finish();
+ }
+
+ /**
+ * Call the post method form C++
+ */
+ public native void postMobileMessageNative(String message);
+
+ /**
+ * Passing messages from JS (instead of the websocket communication).
+ */
+ @JavascriptInterface
+ public void postMobileError(String message) {
+ // TODO handle this
+ Log.d(TAG, "postMobileError: " + message);
+ }
+
+ /**
+ * Passing messages from JS (instead of the websocket communication).
+ */
+ @JavascriptInterface
+ public void postMobileDebug(String message) {
+ // TODO handle this
+ Log.d(TAG, "postMobileDebug: " + message);
+ }
+
+ /**
+ * Passing message the other way around - from Java to the FakeWebSocket in JS.
+ */
+ void callFakeWebsocketOnMessage(final String message) {
+ // call from the UI thread
+ mWebView.post(new Runnable() {
+ public void run() {
+ Log.i(TAG, "Forwarding to the WebView: " + message);
+ mWebView.loadUrl("javascript:window.TheFakeWebSocket.onmessage({'data':" + message + "});");
+ }
+ });
+ }
+
+ /**
+ * return true to pass the message to the native part and false to block the message
+ */
+ boolean interceptMsgFromWebView(String message) {
+ if (message.equals("PRINT")) {
+ mainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ initiatePrint();
+ }
+ });
+ return false;
+ } else if (message.equals("SLIDESHOW")) {
+ initiateSlideShow();
+ return false;
+ }
+ return true;
+ }
+
+ private void initiatePrint() {
+ PrintManager printManager = (PrintManager) getSystemService(PRINT_SERVICE);
+ PrintDocumentAdapter printAdapter = new PrintAdapter(LOActivity.this);
+ printManager.print("Document", printAdapter, new PrintAttributes.Builder().build());
+ }
+
+ private void initiateSlideShow() {
+ final AlertDialog slideShowProgress = new AlertDialog.Builder(this)
+ .setCancelable(false)
+ .setView(R.layout.dialog_loading)
+ .create();
+ new AsyncTask<Void, Void, String>() {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ slideShowProgress.show();
+ }
+
+ @Override
+ protected String doInBackground(Void... voids) {
+ Log.v(TAG, "saving svg for slideshow by " + Thread.currentThread().getName());
+ String slideShowFileUri = new File(getCacheDir(), "slideShow.svg").toURI().toString();
+ saveAs(slideShowFileUri, "svg");
+ return slideShowFileUri;
+ }
+
+ @Override
+ protected void onPostExecute(String slideShowFileUri) {
+ super.onPostExecute(slideShowFileUri);
+ slideShowProgress.dismiss();
+ Intent slideShowActIntent = new Intent(LOActivity.this, SlideShowActivity.class);
+ slideShowActIntent.putExtra(SlideShowActivity.SVG_URI_KEY, slideShowFileUri);
+ startActivity(slideShowActIntent);
+ }
+ }.execute();
+ }
+
+ public native void saveAs(String fileUri, String format);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/PrintAdapter.java b/android/lib/src/main/java/org/libreoffice/androidlib/PrintAdapter.java
similarity index 96%
rename from android/app/src/main/java/org/libreoffice/androidapp/PrintAdapter.java
rename to android/lib/src/main/java/org/libreoffice/androidlib/PrintAdapter.java
index 52f5bcc95..a10349327 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/PrintAdapter.java
+++ b/android/lib/src/main/java/org/libreoffice/androidlib/PrintAdapter.java
@@ -7,7 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-package org.libreoffice.androidapp;
+package org.libreoffice.androidlib;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -28,9 +28,9 @@ import java.util.Objects;
public class PrintAdapter extends PrintDocumentAdapter {
private File printDocFile;
- private MainActivity mainActivity;
+ private LOActivity mainActivity;
- PrintAdapter(MainActivity mainActivity) {
+ PrintAdapter(LOActivity mainActivity) {
this.mainActivity = mainActivity;
}
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/SlideShowActivity.java b/android/lib/src/main/java/org/libreoffice/androidlib/SlideShowActivity.java
similarity index 98%
rename from android/app/src/main/java/org/libreoffice/androidapp/SlideShowActivity.java
rename to android/lib/src/main/java/org/libreoffice/androidlib/SlideShowActivity.java
index 97407eb44..3a957b154 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/SlideShowActivity.java
+++ b/android/lib/src/main/java/org/libreoffice/androidlib/SlideShowActivity.java
@@ -7,7 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-package org.libreoffice.androidapp;
+package org.libreoffice.androidlib;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/lib/src/main/res/layout/activity_main.xml
similarity index 94%
rename from android/app/src/main/res/layout/activity_main.xml
rename to android/lib/src/main/res/layout/activity_main.xml
index 244e1bb99..2810a9af9 100644
--- a/android/app/src/main/res/layout/activity_main.xml
+++ b/android/lib/src/main/res/layout/activity_main.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".MainActivity">
+ tools:context=".LOActivity">
<WebView
android:id="@+id/browser"
diff --git a/android/app/src/main/res/layout/activity_slide_show.xml b/android/lib/src/main/res/layout/activity_slide_show.xml
similarity index 100%
rename from android/app/src/main/res/layout/activity_slide_show.xml
rename to android/lib/src/main/res/layout/activity_slide_show.xml
diff --git a/android/app/src/main/res/layout/dialog_loading.xml b/android/lib/src/main/res/layout/dialog_loading.xml
similarity index 100%
rename from android/app/src/main/res/layout/dialog_loading.xml
rename to android/lib/src/main/res/layout/dialog_loading.xml
diff --git a/android/lib/src/main/res/values/strings.xml b/android/lib/src/main/res/values/strings.xml
new file mode 100644
index 000000000..5651df183
--- /dev/null
+++ b/android/lib/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+<resources>
+ <string name="temp_file_saving_disabled">This file is read-only, saving is disabled.</string>
+ <string name="storage_permission_required">Storage permission is required</string>
+ <string name="failed_to_load_file">Failed to determine the file to load</string>
+
+ <!-- Loading SlideShow Dialog Strings -->
+ <string name="loading">Loading...</string>
+</resources>
\ No newline at end of file
diff --git a/android/settings.gradle b/android/settings.gradle
index e7b4def49..3cbe24935 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -1 +1 @@
-include ':app'
+include ':app', ':lib'
diff --git a/configure.ac b/configure.ac
index c9446f35a..681d5bdde 100644
--- a/configure.ac
+++ b/configure.ac
@@ -790,8 +790,9 @@ AS_IF([test "$ENABLE_IOSAPP" = "true"],
AC_SUBST(IOSAPP_FONTS)
AC_CONFIG_FILES([Makefile
- android/app/liboSettings.gradle
- android/app/src/main/cpp/CMakeLists.txt
+ android/app/appSettings.gradle
+ android/lib/libSettings.gradle
+ android/lib/src/main/cpp/CMakeLists.txt
android/Makefile
gtk/Makefile
ios/config.h
diff --git a/loleaflet/Makefile.am b/loleaflet/Makefile.am
index 2106a0846..5ec53ce0f 100644
--- a/loleaflet/Makefile.am
+++ b/loleaflet/Makefile.am
@@ -152,13 +152,13 @@ build-loleaflet: | $(LOLEAFLET_L10N_DST) \
$(builddir)/dist/loleaflet.html
@echo "build loleaflet completed"
if ENABLE_ANDROIDAPP
- @rm -rf $(abs_top_srcdir)/android/app/src/main/assets/dist
- @cp -a $(builddir)/dist $(abs_top_srcdir)/android/app/src/main/assets/
- @if test -d "$(APP_BRANDING_DIR)" ; then cp -a "$(APP_BRANDING_DIR)/branding.css" "$(APP_BRANDING_DIR)/branding.js" $(abs_top_srcdir)/android/app/src/main/assets/dist/ ; else touch $(abs_top_srcdir)/android/app/src/main/assets/dist/branding.css ; fi
- @if test -d "$(APP_BRANDING_DIR)" ; then cp -a "$(APP_BRANDING_DIR)"/*.svg $(abs_top_srcdir)/android/app/src/main/assets/dist/images/ ; fi
- @if test -d "$(APP_BRANDING_DIR)" ; then cp -a "$(APP_BRANDING_DIR)/toolbar-bg-logo.svg" $(abs_top_srcdir)/android/app/src/main/assets/dist/images/toolbar-bg.svg ; fi
+ @rm -rf $(abs_top_srcdir)/android/lib/src/main/assets/dist
+ @cp -a $(builddir)/dist $(abs_top_srcdir)/android/lib/src/main/assets/
+ @if test -d "$(APP_BRANDING_DIR)" ; then cp -a "$(APP_BRANDING_DIR)/branding.css" "$(APP_BRANDING_DIR)/branding.js" $(abs_top_srcdir)/android/lib/src/main/assets/dist/ ; else touch $(abs_top_srcdir)/android/lib/src/main/assets/dist/branding.css ; fi
+ @if test -d "$(APP_BRANDING_DIR)" ; then cp -a "$(APP_BRANDING_DIR)"/*.svg $(abs_top_srcdir)/android/lib/src/main/assets/dist/images/ ; fi
+ @if test -d "$(APP_BRANDING_DIR)" ; then cp -a "$(APP_BRANDING_DIR)/toolbar-bg-logo.svg" $(abs_top_srcdir)/android/lib/src/main/assets/dist/images/toolbar-bg.svg ; fi
@echo
- @echo "Copied JS, HTML and CSS to the Android project (android/app/src/main/assets/dist)."
+ @echo "Copied JS, HTML and CSS to the Android project (android/lib/src/main/assets/dist)."
@echo
@echo " Now you need to build the actual .apk from Android Studio:"
@echo " Just open the 'android' subdir as a project there and build."
More information about the Libreoffice-commits
mailing list