diff --git a/src/android/java/AndroidManifest.xml b/src/android/java/AndroidManifest.xml
index 6a407dcb6e..48fb23ab28 100644
--- a/src/android/java/AndroidManifest.xml
+++ b/src/android/java/AndroidManifest.xml
@@ -11,8 +11,12 @@
+
+
+
+
-
+
diff --git a/src/android/java/READ-THIS-BEFORE-MANUALLY-ADDING-FILES-TO-PACKAGE.txt b/src/android/java/READ-THIS-BEFORE-MANUALLY-ADDING-FILES-TO-PACKAGE.txt
new file mode 100644
index 0000000000..978417721f
--- /dev/null
+++ b/src/android/java/READ-THIS-BEFORE-MANUALLY-ADDING-FILES-TO-PACKAGE.txt
@@ -0,0 +1,6 @@
+If this package is accessed by Qt Creator, certain changes can be
+overwritten without warning. In particular, Qt Creator may overwrite
+settings which are maintained using its own UI, and files and
+directories containing the string "--Managed_by_Qt_Creator--", as well
+as native libraries whose file names begin with "libQt5" may be
+deleted without warning if they are contained inside this package.
diff --git a/src/android/java/res/values/libs.xml b/src/android/java/res/values/libs.xml
index f47174e3d3..09fa409458 100644
--- a/src/android/java/res/values/libs.xml
+++ b/src/android/java/res/values/libs.xml
@@ -8,4 +8,6 @@
- Qt5Core
+
+
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
index dfb638fbb0..22b34fdbef 100644
--- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
@@ -27,6 +27,11 @@
package org.qtproject.qt5.android.bindings;
import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -47,6 +52,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
+import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.net.Uri;
@@ -89,6 +95,8 @@ public class QtActivity extends Activity
private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
private static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
+ private static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id";
+ private static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id";
private static final String MAIN_LIBRARY_KEY = "main.library";
private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
private static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level";
@@ -120,6 +128,8 @@ public class QtActivity extends Activity
// note that the android style plugin in Qt 5.1 is not fully functional.
private static final int INCOMPATIBLE_MINISTRO_VERSION = 1; // Incompatible Ministro version. Ministro needs to be upgraded.
+ private static final int BUFFER_SIZE = 1024;
+
private ActivityInfo m_activityInfo = null; // activity info object, used to access the libs and the strings
private DexClassLoader m_classLoader = null; // loader object
private String[] m_sources = {"https://files.kde.org/necessitas/ministro/android/necessitas/qt5/latest"}; // Make sure you are using ONLY secure locations
@@ -308,6 +318,92 @@ public class QtActivity extends Activity
errorDialog.show();
}
+ static private void copyFile(InputStream inputStream, OutputStream outputStream)
+ throws IOException
+ {
+ byte[] buffer = new byte[BUFFER_SIZE];
+
+ int count;
+ while ((count = inputStream.read(buffer)) > 0)
+ outputStream.write(buffer, 0, count);
+ }
+
+
+ private void copyAsset(String source, String destination)
+ throws IOException
+ {
+ // Already exists, we don't have to do anything
+ File destinationFile = new File(destination);
+ if (destinationFile.exists())
+ return;
+
+ File parentDirectory = destinationFile.getParentFile();
+ if (!parentDirectory.exists())
+ parentDirectory.mkdirs();
+
+ destinationFile.createNewFile();
+
+ AssetManager assetsManager = getAssets();
+ InputStream inputStream = assetsManager.open(source);
+ OutputStream outputStream = new FileOutputStream(destinationFile);
+ copyFile(inputStream, outputStream);
+ }
+
+ private static void createBundledBinary(String source, String destination)
+ throws IOException
+ {
+ // Already exists, we don't have to do anything
+ File destinationFile = new File(destination);
+ if (destinationFile.exists())
+ return;
+
+ File parentDirectory = destinationFile.getParentFile();
+ if (!parentDirectory.exists())
+ parentDirectory.mkdirs();
+
+ destinationFile.createNewFile();
+
+ InputStream inputStream = new FileInputStream(source);
+ OutputStream outputStream = new FileOutputStream(destinationFile);
+ copyFile(inputStream, outputStream);
+ }
+
+ private void extractBundledPluginsAndImports(String localPrefix)
+ throws IOException
+ {
+ ArrayList libs = new ArrayList();
+
+ {
+ String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
+ java.util.Set keys = m_activityInfo.metaData.keySet();
+ if (m_activityInfo.metaData.containsKey(key)) {
+ String[] list = getResources().getStringArray(m_activityInfo.metaData.getInt(key));
+
+ for (String bundledImportBinary : list) {
+ String[] split = bundledImportBinary.split(":");
+ String sourceFileName = localPrefix + "lib/" + split[0];
+ String destinationFileName = localPrefix + split[1];
+ createBundledBinary(sourceFileName, destinationFileName);
+ }
+ }
+ }
+
+ {
+ String key = BUNDLED_IN_ASSETS_RESOURCE_ID_KEY;
+ if (m_activityInfo.metaData.containsKey(key)) {
+ String[] list = getResources().getStringArray(m_activityInfo.metaData.getInt(key));
+
+ for (String fileName : list) {
+ String[] split = fileName.split(":");
+ String sourceFileName = split[0];
+ String destinationFileName = localPrefix + split[1];
+ copyAsset(sourceFileName, destinationFileName);
+ }
+ }
+
+ }
+ }
+
private void startApp(final boolean firstStart)
{
try {
@@ -328,13 +424,26 @@ public class QtActivity extends Activity
&& m_activityInfo.metaData.getInt("android.app.use_local_qt_libs") == 1) {
ArrayList libraryList = new ArrayList();
+
String localPrefix = "/data/local/tmp/qt/";
if (m_activityInfo.metaData.containsKey("android.app.libs_prefix"))
localPrefix = m_activityInfo.metaData.getString("android.app.libs_prefix");
+ boolean bundlingQtLibs = false;
+ if (m_activityInfo.metaData.containsKey("android.app.bundle_local_qt_libs")
+ && m_activityInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) {
+ localPrefix = getApplicationInfo().dataDir + "/";
+ extractBundledPluginsAndImports(localPrefix);
+ bundlingQtLibs = true;
+ }
+
if (m_qtLibs != null) {
- for (int i=0;i 0) {