summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconfigure26
-rw-r--r--mkspecs/features/mac/sdk.prf2
-rw-r--r--mkspecs/features/qt.prf2
-rw-r--r--mkspecs/features/qt_functions.prf10
-rw-r--r--qmake/generators/win32/msvc_objectmodel.cpp4
-rw-r--r--qmake/generators/win32/msvc_objectmodel.h21
-rw-r--r--src/android/jar/jar.pri3
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java3
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java121
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java8
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java182
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java701
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtActivityLoader.java193
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java16
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java655
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtService.java153
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtServiceLoader.java77
-rw-r--r--src/android/templates/AndroidManifest.xml55
-rw-r--r--src/corelib/global/qglobal.cpp14
-rw-r--r--src/corelib/global/qnamespace.h1
-rw-r--r--src/corelib/global/qnamespace.qdoc4
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp17
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp55
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h1
-rw-r--r--src/corelib/mimetypes/qmimeglobpattern_p.h10
-rw-r--r--src/corelib/mimetypes/qmimemagicrule.cpp212
-rw-r--r--src/corelib/mimetypes/qmimemagicrule_p.h47
-rw-r--r--src/corelib/mimetypes/qmimemagicrulematcher_p.h8
-rw-r--r--src/corelib/thread/qthread.cpp8
-rw-r--r--src/corelib/tools/qdatetime.cpp15
-rw-r--r--src/corelib/tools/qdatetime.h5
-rw-r--r--src/corelib/tools/qdatetimeparser.cpp45
-rw-r--r--src/gui/itemmodels/qstandarditemmodel.cpp1
-rw-r--r--src/gui/kernel/qshortcutmap.cpp2
-rw-r--r--src/gui/kernel/qstylehints.cpp22
-rw-r--r--src/gui/kernel/qstylehints.h4
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp77
-rw-r--r--src/gui/opengl/qopenglframebufferobject.h14
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp50
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h10
-rw-r--r--src/plugins/bearer/connman/qconnmanservice_linux_p.h5
-rw-r--r--src/plugins/bearer/linux_common/qofonoservice_linux_p.h7
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp23
-rw-r--r--src/plugins/platforms/android/androidjnimain.h1
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp27
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidsystemlocale.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp37
-rw-r--r--src/printsupport/dialogs/qprintpreviewdialog.cpp4
-rw-r--r--src/printsupport/kernel/qpaintengine_alpha.cpp4
-rw-r--r--src/printsupport/kernel/qprintdevice.cpp6
-rw-r--r--src/printsupport/kernel/qprinter.cpp16
-rw-r--r--src/printsupport/widgets/qprintpreviewwidget.cpp16
-rw-r--r--src/sql/drivers/oci/qsql_oci.cpp80
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.cpp21
-rw-r--r--src/sql/kernel/qsqlcachedresult.cpp1
-rw-r--r--src/sql/kernel/qsqlresult.cpp4
-rw-r--r--src/sql/models/qsqltablemodel.cpp3
-rw-r--r--src/testlib/testlib.pro4
-rw-r--r--src/widgets/dialogs/qcolordialog.cpp7
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp7
-rw-r--r--src/widgets/dialogs/qfontdialog.cpp7
-rw-r--r--src/widgets/itemviews/qdirmodel.cpp25
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.cpp9
-rw-r--r--tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro6
-rw-r--r--tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp4
-rw-r--r--tools/configure/configureapp.cpp22
67 files changed, 2051 insertions, 1153 deletions
diff --git a/configure b/configure
index 55b771cb20..dc569d747c 100755
--- a/configure
+++ b/configure
@@ -3087,7 +3087,7 @@ elif [ $COMMERCIAL_USER = "yes" ]; then
exit 1
fi
elif [ $COMMERCIAL_USER = "no" ]; then
- # Open Source edition - may only be used under the terms of the LGPLv3 or LGPLv21.
+ # Open Source edition - may only be used under the terms of the LGPLv3 or GPLv2.
Licensee="Open Source"
Edition="OpenSource"
EditionString="Open Source"
@@ -3103,15 +3103,15 @@ if [ "$Edition" = "OpenSource" ]; then
while true; do
if [ "$CFG_ANDROID_STYLE_ASSETS" = "no" ] || [ "$XPLATFORM_ANDROID" = "no" ]; then
echo "You are licensed to use this software under the terms of"
- echo "the Lesser GNU General Public License (LGPL) versions 2.1."
- echo "You are also licensed to use this software under the terms of"
echo "the GNU Lesser General Public License (LGPL) versions 3."
+ echo "You are also licensed to use this software under the terms of"
+ echo "the GNU General Public License (GPL) versions 2."
affix="either"
- showLGPL2="yes"
+ showGPL2="yes"
else
echo "You are licensed to use this software under the terms of"
echo "the GNU Lesser General Public License (LGPL) versions 3."
- showLGPL2="no"
+ showGPL2="no"
affix="the"
fi
@@ -3120,11 +3120,11 @@ if [ "$Edition" = "OpenSource" ]; then
echo "You have already accepted the terms of the $EditionString license."
acceptance=yes
else
- if [ -f "$relpath/LICENSE.LGPLv3" ]; then
- echo "Type '3' to view the GNU Lesser General Public License version 3."
+ if [ -f "$relpath/LICENSE.LGPL3" ]; then
+ echo "Type 'L' to view the GNU Lesser General Public License version 3."
fi
- if [ "$showLGPL2" = "yes" ]; then
- echo "Type 'L' to view the Lesser GNU General Public License version 2.1."
+ if [ "$showGPL2" = "yes" ]; then
+ echo "Type 'G' to view the GNU General Public License version 2."
fi
echo "Type 'yes' to accept this license offer."
echo "Type 'no' to decline this license offer."
@@ -3139,10 +3139,10 @@ if [ "$Edition" = "OpenSource" ]; then
echo "You are not licensed to use this software."
echo
exit 1
- elif [ "$acceptance" = "3" ]; then
- more "$relpath/LICENSE.LGPLv3"
- elif [ "$acceptance" = "L" ] && [ "$showLGPL2" = "yes" ]; then
- more "$relpath/LICENSE.LGPLv21"
+ elif [ "$acceptance" = "L" ]; then
+ more "$relpath/LICENSE.LGPL3"
+ elif [ "$acceptance" = "G" ] && [ "$showGPL2" = "yes" ]; then
+ more "$relpath/LICENSE.GPL2"
fi
done
elif [ "$Edition" = "Preview" ]; then
diff --git a/mkspecs/features/mac/sdk.prf b/mkspecs/features/mac/sdk.prf
index 46ed51deb4..ab37b1740f 100644
--- a/mkspecs/features/mac/sdk.prf
+++ b/mkspecs/features/mac/sdk.prf
@@ -17,7 +17,7 @@ defineReplace(xcodeSDKInfo) {
cache(QMAKE_MAC_SDK.$${sdk}.$${info}, set stash, QMAKE_MAC_SDK.$${sdk}.$${info})
}
- return($$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.$${info}))
+ return($$eval(QMAKE_MAC_SDK.$${sdk}.$${info}))
}
QMAKE_MAC_SDK_PATH = $$xcodeSDKInfo(Path)
diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf
index b53617ba2a..4b40451c96 100644
--- a/mkspecs/features/qt.prf
+++ b/mkspecs/features/qt.prf
@@ -122,7 +122,7 @@ for(ever) {
QMAKE_FRAMEWORKPATH *= $$MODULE_FRAMEWORKS
!isEmpty(MODULE_MODULE) {
contains(MODULE_CONFIG, lib_bundle) {
- LIBS$$var_sfx += -framework $${MODULE_MODULE}$$qtFrameworkPlatformTargetSuffix()
+ LIBS$$var_sfx += -framework $$MODULE_MODULE
} else {
!isEmpty(MODULE_LIBS_ADD): \
LIBS$$var_sfx += -L$$MODULE_LIBS_ADD
diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf
index 0046cce9ad..2756f90b01 100644
--- a/mkspecs/features/qt_functions.prf
+++ b/mkspecs/features/qt_functions.prf
@@ -14,16 +14,6 @@ defineReplace(qtPlatformTargetSuffix) {
return($$suffix)
}
-# suffix for the -framework linker flag when the exectuable's name
-# differs from the bundle's, for example -framework QtCore,_debug
-# links to QtCore.framework/QtCore_debug
-defineReplace(qtFrameworkPlatformTargetSuffix) {
- suffix = $$qtPlatformTargetSuffix()
- !isEmpty(suffix): \
- suffix = ,$$suffix
- return($$suffix)
-}
-
defineReplace(qtLibraryTarget) {
LIBRARY_NAME = $$1
CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework) {
diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp
index cc6e5754ec..5e655464b7 100644
--- a/qmake/generators/win32/msvc_objectmodel.cpp
+++ b/qmake/generators/win32/msvc_objectmodel.cpp
@@ -1758,10 +1758,6 @@ VCManifestTool::VCManifestTool()
{
}
-VCManifestTool::~VCManifestTool()
-{
-}
-
bool VCManifestTool::parseOption(const char *option)
{
Q_UNUSED(option);
diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h
index 35aa288887..dfbfaacfa8 100644
--- a/qmake/generators/win32/msvc_objectmodel.h
+++ b/qmake/generators/win32/msvc_objectmodel.h
@@ -477,7 +477,7 @@ class VCCLCompilerTool : public VCToolBase
public:
// Functions
VCCLCompilerTool();
- virtual ~VCCLCompilerTool(){}
+
bool parseOption(const char* option);
// Variables
@@ -574,7 +574,7 @@ class VCLinkerTool : public VCToolBase
public:
// Functions
VCLinkerTool();
- virtual ~VCLinkerTool(){}
+
bool parseOption(const char* option);
// Variables
@@ -668,7 +668,7 @@ class VCManifestTool : public VCToolBase
{
public:
VCManifestTool();
- ~VCManifestTool();
+
bool parseOption(const char* option);
triState EmbedManifest;
@@ -679,7 +679,7 @@ class VCMIDLTool : public VCToolBase
public:
// Functions
VCMIDLTool();
- virtual ~VCMIDLTool(){}
+
bool parseOption(const char* option);
// Variables
@@ -733,7 +733,7 @@ class VCLibrarianTool : public VCToolBase
public:
// Functions
VCLibrarianTool();
- virtual ~VCLibrarianTool(){}
+
bool parseOption(const char*){ return false; }
// Variables
@@ -754,7 +754,7 @@ class VCCustomBuildTool : public VCToolBase
public:
// Functions
VCCustomBuildTool();
- virtual ~VCCustomBuildTool(){}
+
bool parseOption(const char*){ return false; }
// Variables
@@ -773,7 +773,7 @@ class VCResourceCompilerTool : public VCToolBase
public:
// Functions
VCResourceCompilerTool();
- virtual ~VCResourceCompilerTool(){}
+
bool parseOption(const char*){ return false; }
// Variables
@@ -794,7 +794,6 @@ class VCDeploymentTool
public:
// Functions
VCDeploymentTool();
- virtual ~VCDeploymentTool() {}
// Variables
QString DeploymentTag;
@@ -808,7 +807,7 @@ class VCEventTool : public VCToolBase
protected:
// Functions
VCEventTool(const QString &eventName);
- virtual ~VCEventTool(){}
+
bool parseOption(const char*){ return false; }
public:
@@ -825,28 +824,24 @@ class VCPostBuildEventTool : public VCEventTool
{
public:
VCPostBuildEventTool();
- ~VCPostBuildEventTool(){}
};
class VCPreBuildEventTool : public VCEventTool
{
public:
VCPreBuildEventTool();
- ~VCPreBuildEventTool(){}
};
class VCPreLinkEventTool : public VCEventTool
{
public:
VCPreLinkEventTool();
- ~VCPreLinkEventTool(){}
};
class VCWinDeployQtTool : public VCToolBase
{
public:
VCWinDeployQtTool() {}
- ~VCWinDeployQtTool() {}
protected:
bool parseOption(const char *) { return false; }
diff --git a/src/android/jar/jar.pri b/src/android/jar/jar.pri
index b45b353f95..58caacb837 100644
--- a/src/android/jar/jar.pri
+++ b/src/android/jar/jar.pri
@@ -16,7 +16,8 @@ JAVASOURCES += \
$$PATHPREFIX/QtNative.java \
$$PATHPREFIX/QtNativeLibrariesDir.java \
$$PATHPREFIX/QtSurface.java \
- $$PATHPREFIX/ExtractStyle.java
+ $$PATHPREFIX/ExtractStyle.java \
+ $$PATHPREFIX/QtServiceDelegate.java
# install
target.path = $$[QT_INSTALL_PREFIX]/jar
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
index 14c7a03a36..c434cc24b3 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
@@ -953,6 +953,7 @@ public class QtActivityDelegate
{
if (m_quitApp) {
QtNative.terminateQt();
+ QtNative.setActivity(null, null);
if (m_debuggerProcess != null)
m_debuggerProcess.destroy();
System.exit(0);// FIXME remove it or find a better way
@@ -1200,6 +1201,8 @@ public class QtActivityDelegate
private void setActionBarVisibility(boolean visible)
{
+ if (m_activity.getActionBar() == null)
+ return;
if (ViewConfiguration.get(m_activity).hasPermanentMenuKey() || !visible)
m_activity.getActionBar().hide();
else
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
index d9be4c7d9f..5d4f6e791a 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+** Copyright (C) 2016 BogDan Vatra <bogdan@kde.org>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -45,6 +45,7 @@ import java.util.ArrayList;
import java.util.concurrent.Semaphore;
import android.app.Activity;
+import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -72,7 +73,9 @@ public class QtNative
{
private static Activity m_activity = null;
private static boolean m_activityPaused = false;
+ private static Service m_service = null;
private static QtActivityDelegate m_activityDelegate = null;
+ private static QtServiceDelegate m_serviceDelegate = null;
public static Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations
public static final String QtTAG = "Qt JAVA"; // string used for Log.x
@@ -115,6 +118,14 @@ public class QtNative
}
}
+ public static Service service()
+ {
+ synchronized (m_mainActivityMutex) {
+ return m_service;
+ }
+ }
+
+
public static QtActivityDelegate activityDelegate()
{
synchronized (m_mainActivityMutex) {
@@ -122,6 +133,13 @@ public class QtNative
}
}
+ public static QtServiceDelegate serviceDelegate()
+ {
+ synchronized (m_mainActivityMutex) {
+ return m_serviceDelegate;
+ }
+ }
+
public static boolean openURL(String url, String mime)
{
boolean ok = true;
@@ -186,6 +204,14 @@ public class QtNative
}
}
+ public static void setService(Service qtMainService, QtServiceDelegate qtServiceDelegate)
+ {
+ synchronized (m_mainActivityMutex) {
+ m_service = qtMainService;
+ m_serviceDelegate = qtServiceDelegate;
+ }
+ }
+
public static void setApplicationState(int state)
{
synchronized (m_mainActivityMutex) {
@@ -319,7 +345,11 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activity.finish();
+ quitQtAndroidPlugin();
+ if (m_activity != null)
+ m_activity.finish();
+ if (m_service != null)
+ m_service.stopSelf();
}
});
}
@@ -452,7 +482,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.updateSelection(selStart, selEnd, candidatesStart, candidatesEnd);
+ if (m_activityDelegate != null)
+ m_activityDelegate.updateSelection(selStart, selEnd, candidatesStart, candidatesEnd);
}
});
}
@@ -467,7 +498,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType);
+ if (m_activityDelegate != null)
+ m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType);
}
});
}
@@ -477,7 +509,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.resetSoftwareKeyboard();
+ if (m_activityDelegate != null)
+ m_activityDelegate.resetSoftwareKeyboard();
}
});
}
@@ -487,7 +520,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.hideSoftwareKeyboard();
+ if (m_activityDelegate != null)
+ m_activityDelegate.hideSoftwareKeyboard();
}
});
}
@@ -497,7 +531,9 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.setFullScreen(fullScreen);
+ if (m_activityDelegate != null) {
+ m_activityDelegate.setFullScreen(fullScreen);
+ }
updateWindow();
}
});
@@ -505,34 +541,44 @@ public class QtNative
private static void registerClipboardManager()
{
- final Semaphore semaphore = new Semaphore(0);
- runAction(new Runnable() {
- @Override
- public void run() {
- m_clipboardManager = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
- semaphore.release();
+ if (m_service == null || m_activity != null) { // Avoid freezing if only service
+ final Semaphore semaphore = new Semaphore(0);
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ if (m_activity != null)
+ m_clipboardManager = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ semaphore.release();
+ }
+ });
+ try {
+ semaphore.acquire();
+ } catch (Exception e) {
+ e.printStackTrace();
}
- });
- try {
- semaphore.acquire();
- } catch (Exception e) {
- e.printStackTrace();
}
}
private static void setClipboardText(String text)
{
- m_clipboardManager.setText(text);
+ if (m_clipboardManager != null)
+ m_clipboardManager.setText(text);
}
private static boolean hasClipboardText()
{
- return m_clipboardManager.hasText();
+ if (m_clipboardManager != null)
+ return m_clipboardManager.hasText();
+ else
+ return false;
}
private static String getClipboardText()
{
- return m_clipboardManager.getText().toString();
+ if (m_clipboardManager != null)
+ return m_clipboardManager.getText().toString();
+ else
+ return "";
}
private static void openContextMenu(final int x, final int y, final int w, final int h)
@@ -540,7 +586,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.openContextMenu(x, y, w, h);
+ if (m_activityDelegate != null)
+ m_activityDelegate.openContextMenu(x, y, w, h);
}
});
}
@@ -550,7 +597,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.closeContextMenu();
+ if (m_activityDelegate != null)
+ m_activityDelegate.closeContextMenu();
}
});
}
@@ -560,7 +608,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.resetOptionsMenu();
+ if (m_activityDelegate != null)
+ m_activityDelegate.resetOptionsMenu();
}
});
}
@@ -570,7 +619,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activity.openOptionsMenu();
+ if (m_activity != null)
+ m_activity.openOptionsMenu();
}
});
}
@@ -607,7 +657,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.createSurface(id, onTop, x, y, w, h, imageDepth);
+ if (m_activityDelegate != null)
+ m_activityDelegate.createSurface(id, onTop, x, y, w, h, imageDepth);
}
});
}
@@ -617,7 +668,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.insertNativeView(id, view, x, y, w, h);
+ if (m_activityDelegate != null)
+ m_activityDelegate.insertNativeView(id, view, x, y, w, h);
}
});
}
@@ -627,7 +679,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.setSurfaceGeometry(id, x, y, w, h);
+ if (m_activityDelegate != null)
+ m_activityDelegate.setSurfaceGeometry(id, x, y, w, h);
}
});
}
@@ -637,7 +690,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.bringChildToFront(id);
+ if (m_activityDelegate != null)
+ m_activityDelegate.bringChildToFront(id);
}
});
}
@@ -647,7 +701,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.bringChildToBack(id);
+ if (m_activityDelegate != null)
+ m_activityDelegate.bringChildToBack(id);
}
});
}
@@ -657,7 +712,8 @@ public class QtNative
runAction(new Runnable() {
@Override
public void run() {
- m_activityDelegate.destroySurface(id);
+ if (m_activityDelegate != null)
+ m_activityDelegate.destroySurface(id);
}
});
}
@@ -737,4 +793,7 @@ public class QtNative
public static native void onNewIntent(Intent data);
public static native void runPendingCppRunnables();
+
+ private static native void setNativeActivity(Activity activity);
+ private static native void setNativeService(Service service);
}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java b/src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java
index 8481baec54..ff3bf19383 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNativeLibrariesDir.java
@@ -40,17 +40,17 @@
package org.qtproject.qt5.android;
-import android.app.Activity;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
public class QtNativeLibrariesDir {
- public static String nativeLibrariesDir(Activity activity)
+ public static String nativeLibrariesDir(Context context)
{
String m_nativeLibraryDir = null;
try {
- ApplicationInfo ai = activity.getPackageManager().getApplicationInfo(activity.getPackageName(), 0);
- m_nativeLibraryDir = ai.nativeLibraryDir+"/";
+ ApplicationInfo ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
+ m_nativeLibraryDir = ai.nativeLibraryDir + "/";
} catch (NameNotFoundException e) {
e.printStackTrace();
}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java
new file mode 100644
index 0000000000..634658eefb
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 BogDan Vatra <bogdan@kde.org>
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Android port of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.graphics.drawable.ColorDrawable;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.text.method.MetaKeyKeyListener;
+import android.util.Base64;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+public class QtServiceDelegate
+{
+ private static final String NATIVE_LIBRARIES_KEY = "native.libraries";
+ private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
+ private static final String MAIN_LIBRARY_KEY = "main.library";
+ private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
+ private static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
+ private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
+ private static final String APP_DISPLAY_METRIC_SCREEN_DESKTOP_KEY = "display.screen.desktop";
+ private static final String APP_DISPLAY_METRIC_SCREEN_XDPI_KEY = "display.screen.dpi.x";
+ private static final String APP_DISPLAY_METRIC_SCREEN_YDPI_KEY = "display.screen.dpi.y";
+ private static final String APP_DISPLAY_METRIC_SCREEN_DENSITY_KEY = "display.screen.density";
+
+ private Service m_service = null;
+ private String m_mainLib;
+ private static String m_environmentVariables = null;
+ private static String m_applicationParameters = null;
+
+ public boolean loadApplication(Service service, ClassLoader classLoader, Bundle loaderParams)
+ {
+ /// check parameters integrity
+ if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY)
+ || !loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)) {
+ return false;
+ }
+
+ m_service = service;
+ QtNative.setService(m_service, this);
+ QtNative.setClassLoader(classLoader);
+
+ QtNative.setApplicationDisplayMetrics(10, 10, 10, 10, 120, 120, 1.0, 1.0);
+
+ if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) {
+ for (String className: loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY)) {
+ if (className.length() == 0)
+ continue;
+
+ try {
+ Class<?> initClass = classLoader.loadClass(className);
+ Object staticInitDataObject = initClass.newInstance(); // create an instance
+ Method m = initClass.getMethod("setService", Service.class, Object.class);
+ m.invoke(staticInitDataObject, m_service, this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ QtNative.loadQtLibraries(loaderParams.getStringArrayList(NATIVE_LIBRARIES_KEY));
+ ArrayList<String> libraries = loaderParams.getStringArrayList(BUNDLED_LIBRARIES_KEY);
+ QtNative.loadBundledLibraries(libraries, QtNativeLibrariesDir.nativeLibrariesDir(m_service));
+ m_mainLib = loaderParams.getString(MAIN_LIBRARY_KEY);
+
+ m_environmentVariables = loaderParams.getString(ENVIRONMENT_VARIABLES_KEY);
+ String additionalEnvironmentVariables = "QT_ANDROID_FONTS_MONOSPACE=Droid Sans Mono;Droid Sans;Droid Sans Fallback"
+ + "\tQT_ANDROID_FONTS_SERIF=Droid Serif"
+ + "\tHOME=" + m_service.getFilesDir().getAbsolutePath()
+ + "\tTMPDIR=" + m_service.getFilesDir().getAbsolutePath();
+ if (Build.VERSION.SDK_INT < 14)
+ additionalEnvironmentVariables += "\tQT_ANDROID_FONTS=Droid Sans;Droid Sans Fallback";
+ else
+ additionalEnvironmentVariables += "\tQT_ANDROID_FONTS=Roboto;Droid Sans;Droid Sans Fallback";
+
+ if (m_environmentVariables != null && m_environmentVariables.length() > 0)
+ m_environmentVariables = additionalEnvironmentVariables + "\t" + m_environmentVariables;
+ else
+ m_environmentVariables = additionalEnvironmentVariables;
+
+ if (loaderParams.containsKey(APPLICATION_PARAMETERS_KEY))
+ m_applicationParameters = loaderParams.getString(APPLICATION_PARAMETERS_KEY);
+ else
+ m_applicationParameters = "";
+
+ return true;
+ }
+
+ public boolean startApplication()
+ {
+ // start application
+ try {
+ String nativeLibraryDir = QtNativeLibrariesDir.nativeLibrariesDir(m_service);
+ QtNative.startApplication(m_applicationParameters,
+ m_environmentVariables,
+ m_mainLib,
+ nativeLibraryDir);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public void onDestroy()
+ {
+ QtNative.setService(null, null);
+ }
+}
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 4c2e612238..678420dae7 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
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2013, BogDan Vatra <bogdan@kde.org>
+ Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
Contact: http://www.qt.io/licensing/
Commercial License Usage
@@ -36,47 +36,20 @@
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.io.DataOutputStream;
-import java.io.DataInputStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.kde.necessitas.ministro.IMinistro;
-import org.kde.necessitas.ministro.IMinistroCallback;
-
import android.app.Activity;
-import android.app.AlertDialog;
import android.app.Dialog;
-import android.content.ComponentName;
+import android.app.Fragment;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageInfo;
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.graphics.drawable.ColorDrawable;
-import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
import android.util.AttributeSet;
-import android.util.Log;
+import android.view.ActionMode;
+import android.view.ActionMode.Callback;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
@@ -84,601 +57,25 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
-import dalvik.system.DexClassLoader;
-
-//@ANDROID-11
-import android.app.Fragment;
-import android.view.ActionMode;
-import android.view.ActionMode.Callback;
-//@ANDROID-11
public class QtActivity extends Activity
{
- private final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro instalation is finished
- private static final int MINISTRO_API_LEVEL = 5; // Ministro api level (check IMinistro.aidl file)
- private static final int NECESSITAS_API_LEVEL = 2; // Necessitas api level used by platform plugin
- private static final int QT_VERSION = 0x050100; // This app requires at least Qt version 5.1.0
-
- private static final String ERROR_CODE_KEY = "error.code";
- private static final String ERROR_MESSAGE_KEY = "error.message";
- private static final String DEX_PATH_KEY = "dex.path";
- private static final String LIB_PATH_KEY = "lib.path";
- private static final String LOADER_CLASS_NAME_KEY = "loader.class.name";
- private static final String NATIVE_LIBRARIES_KEY = "native.libraries";
- 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";
- private static final String EXTRACT_STYLE_KEY = "extract.android.style";
-
- /// Ministro server parameter keys
- private static final String REQUIRED_MODULES_KEY = "required.modules";
- private static final String APPLICATION_TITLE_KEY = "application.title";
- private static final String MINIMUM_MINISTRO_API_KEY = "minimum.ministro.api";
- private static final String MINIMUM_QT_VERSION_KEY = "minimum.qt.version";
- private static final String SOURCES_KEY = "sources"; // needs MINISTRO_API_LEVEL >=3 !!!
- // Use this key to specify any 3rd party sources urls
- // Ministro will download these repositories into their
- // own folders, check http://community.kde.org/Necessitas/Ministro
- // for more details.
-
- private static final String REPOSITORY_KEY = "repository"; // use this key to overwrite the default ministro repsitory
- private static final String ANDROID_THEMES_KEY = "android.themes"; // themes that your application uses
-
-
- public String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application,
- // the parameters must not contain any white spaces
- // and must be separated with "\t"
- // e.g "-param1\t-param2=value2\t-param3\tvalue3"
-
- public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_STYLE=1\tQT_USE_ANDROID_NATIVE_DIALOGS=1\t";
- // use this variable to add any environment variables to your application.
- // the env vars must be separated with "\t"
- // e.g. "ENV_VAR1=1\tENV_VAR2=2\t"
- // Currently the following vars are used by the android plugin:
- // * QT_USE_ANDROID_NATIVE_STYLE - 1 to use the android widget style if available.
- // * QT_USE_ANDROID_NATIVE_DIALOGS -1 to use the android native dialogs.
-
- public String[] QT_ANDROID_THEMES = null; // A list with all themes that your application want to use.
- // The name of the theme must be the same with any theme from
- // http://developer.android.com/reference/android/R.style.html
- // The most used themes are:
- // * "Theme" - (fallback) check http://developer.android.com/reference/android/R.style.html#Theme
- // * "Theme_Black" - check http://developer.android.com/reference/android/R.style.html#Theme_Black
- // * "Theme_Light" - (default for API <=10) check http://developer.android.com/reference/android/R.style.html#Theme_Light
- // * "Theme_Holo" - check http://developer.android.com/reference/android/R.style.html#Theme_Holo
- // * "Theme_Holo_Light" - (default for API 11-13) check http://developer.android.com/reference/android/R.style.html#Theme_Holo_Light
- // * "Theme_DeviceDefault" - check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault
- // * "Theme_DeviceDefault_Light" - (default for API 14+) check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault_Light
-
- public String QT_ANDROID_DEFAULT_THEME = null; // sets the default theme.
-
- 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://download.qt-project.org/ministro/android/qt5/qt-5.2"}; // Make sure you are using ONLY secure locations
- private String m_repository = "default"; // Overwrites the default Ministro repository
- // Possible values:
- // * default - Ministro default repository set with "Ministro configuration tool".
- // By default the stable version is used. Only this or stable repositories should
- // be used in production.
- // * stable - stable repository, only this and default repositories should be used
- // in production.
- // * testing - testing repository, DO NOT use this repository in production,
- // this repository is used to push a new release, and should be used to test your application.
- // * unstable - unstable repository, DO NOT use this repository in production,
- // this repository is used to push Qt snapshots.
- private String[] m_qtLibs = null; // required qt libs
- private int m_displayDensity = -1;
-
+ QtActivityLoader m_loader;
public QtActivity()
{
+ m_loader = new QtActivityLoader(this);
if (Build.VERSION.SDK_INT >= 21) {
- QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"};
- QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light";
+ m_loader.QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"};
+ m_loader.QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light";
} else {
- QT_ANDROID_THEMES = new String[] {"Theme_DeviceDefault_Light"};
- QT_ANDROID_DEFAULT_THEME = "Theme_DeviceDefault_Light";
+ m_loader.QT_ANDROID_THEMES = new String[] {"Theme_DeviceDefault_Light"};
+ m_loader.QT_ANDROID_DEFAULT_THEME = "Theme_DeviceDefault_Light";
}
}
- // this function is used to load and start the loader
- private void loadApplication(Bundle loaderParams)
- {
- try {
- final int errorCode = loaderParams.getInt(ERROR_CODE_KEY);
- if (errorCode != 0) {
- if (errorCode == INCOMPATIBLE_MINISTRO_VERSION) {
- downloadUpgradeMinistro(loaderParams.getString(ERROR_MESSAGE_KEY));
- return;
- }
-
- // fatal error, show the error and quit
- AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create();
- errorDialog.setMessage(loaderParams.getString(ERROR_MESSAGE_KEY));
- errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- });
- errorDialog.show();
- return;
- }
-
- // add all bundled Qt libs to loader params
- ArrayList<String> libs = new ArrayList<String>();
- if ( m_activityInfo.metaData.containsKey("android.app.bundled_libs_resource_id") )
- libs.addAll(Arrays.asList(getResources().getStringArray(m_activityInfo.metaData.getInt("android.app.bundled_libs_resource_id"))));
-
- String libName = null;
- if ( m_activityInfo.metaData.containsKey("android.app.lib_name") ) {
- libName = m_activityInfo.metaData.getString("android.app.lib_name");
- loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function
- }
-
- loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs);
- loaderParams.putInt(NECESSITAS_API_LEVEL_KEY, NECESSITAS_API_LEVEL);
-
- // load and start QtLoader class
- m_classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files
- getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written.
- loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists)
- getClassLoader()); // parent loader
-
- @SuppressWarnings("rawtypes")
- Class loaderClass = m_classLoader.loadClass(loaderParams.getString(LOADER_CLASS_NAME_KEY)); // load QtLoader class
- Object qtLoader = loaderClass.newInstance(); // create an instance
- Method prepareAppMethod = qtLoader.getClass().getMethod("loadApplication",
- Activity.class,
- ClassLoader.class,
- Bundle.class);
- if (!(Boolean)prepareAppMethod.invoke(qtLoader, this, m_classLoader, loaderParams))
- throw new Exception("");
-
- QtApplication.setQtActivityDelegate(qtLoader);
-
- // now load the application library so it's accessible from this class loader
- if (libName != null)
- System.loadLibrary(libName);
-
- Method startAppMethod=qtLoader.getClass().getMethod("startApplication");
- if (!(Boolean)startAppMethod.invoke(qtLoader))
- throw new Exception("");
-
- } catch (Exception e) {
- e.printStackTrace();
- AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create();
- if (m_activityInfo.metaData.containsKey("android.app.fatal_error_msg"))
- errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.fatal_error_msg"));
- else
- errorDialog.setMessage("Fatal error, your application can't be started.");
-
- errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- });
- errorDialog.show();
- }
- }
-
- private ServiceConnection m_ministroConnection=new ServiceConnection() {
- private IMinistro m_service = null;
- @Override
- public void onServiceConnected(ComponentName name, IBinder service)
- {
- m_service = IMinistro.Stub.asInterface(service);
- try {
- if (m_service != null) {
- Bundle parameters = new Bundle();
- parameters.putStringArray(REQUIRED_MODULES_KEY, m_qtLibs);
- parameters.putString(APPLICATION_TITLE_KEY, (String)QtActivity.this.getTitle());
- parameters.putInt(MINIMUM_MINISTRO_API_KEY, MINISTRO_API_LEVEL);
- parameters.putInt(MINIMUM_QT_VERSION_KEY, QT_VERSION);
- parameters.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES);
- if (APPLICATION_PARAMETERS != null)
- parameters.putString(APPLICATION_PARAMETERS_KEY, APPLICATION_PARAMETERS);
- parameters.putStringArray(SOURCES_KEY, m_sources);
- parameters.putString(REPOSITORY_KEY, m_repository);
- if (QT_ANDROID_THEMES != null)
- parameters.putStringArray(ANDROID_THEMES_KEY, QT_ANDROID_THEMES);
- m_service.requestLoader(m_ministroCallback, parameters);
- }
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- private IMinistroCallback m_ministroCallback = new IMinistroCallback.Stub() {
- // this function is called back by Ministro.
- @Override
- public void loaderReady(final Bundle loaderParams) throws RemoteException {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- unbindService(m_ministroConnection);
- loadApplication(loaderParams);
- }
- });
- }
- };
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- m_service = null;
- }
- };
-
- private void downloadUpgradeMinistro(String msg)
- {
- AlertDialog.Builder downloadDialog = new AlertDialog.Builder(this);
- downloadDialog.setMessage(msg);
- downloadDialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- try {
- Uri uri = Uri.parse("market://search?q=pname:org.kde.necessitas.ministro");
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- startActivityForResult(intent, MINISTRO_INSTALL_REQUEST_CODE);
- } catch (Exception e) {
- e.printStackTrace();
- ministroNotFound();
- }
- }
- });
-
- downloadDialog.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- QtActivity.this.finish();
- }
- });
- downloadDialog.show();
- }
-
- private void ministroNotFound()
- {
- AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create();
-
- if (m_activityInfo.metaData.containsKey("android.app.ministro_not_found_msg"))
- errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.ministro_not_found_msg"));
- else
- errorDialog.setMessage("Can't find Ministro service.\nThe application can't start.");
-
- errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- });
- 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);
-
- inputStream.close();
- outputStream.close();
- }
-
- 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);
-
- inputStream.close();
- outputStream.close();
- }
-
- private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion)
- {
- File versionFile = new File(pluginsPrefix + "cache.version");
-
- long cacheVersion = 0;
- if (versionFile.exists() && versionFile.canRead()) {
- try {
- DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile));
- cacheVersion = inputStream.readLong();
- inputStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (cacheVersion != packageVersion) {
- deleteRecursively(new File(pluginsPrefix));
- return true;
- } else {
- return false;
- }
- }
-
- private void extractBundledPluginsAndImports(String pluginsPrefix)
- throws IOException
- {
- ArrayList<String> libs = new ArrayList<String>();
-
- String libsDir = getApplicationInfo().nativeLibraryDir + "/";
-
- long packageVersion = -1;
- try {
- PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
- packageVersion = packageInfo.lastUpdateTime;
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion))
- return;
-
- {
- File versionFile = new File(pluginsPrefix + "cache.version");
-
- File parentDirectory = versionFile.getParentFile();
- if (!parentDirectory.exists())
- parentDirectory.mkdirs();
-
- versionFile.createNewFile();
-
- DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile));
- outputStream.writeLong(packageVersion);
- outputStream.close();
- }
-
- {
- String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
- java.util.Set<String> 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 = libsDir + split[0];
- String destinationFileName = pluginsPrefix + 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 = pluginsPrefix + split[1];
- copyAsset(sourceFileName, destinationFileName);
- }
- }
-
- }
- }
-
- private void deleteRecursively(File directory)
- {
- File[] files = directory.listFiles();
- if (files != null) {
- for (File file : files) {
- if (file.isDirectory())
- deleteRecursively(file);
- else
- file.delete();
- }
-
- directory.delete();
- }
- }
-
- private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix)
- {
- File newCache = new File(localPrefix);
- if (!newCache.exists()) {
- {
- File oldPluginsCache = new File(oldLocalPrefix + "plugins/");
- if (oldPluginsCache.exists() && oldPluginsCache.isDirectory())
- deleteRecursively(oldPluginsCache);
- }
-
- {
- File oldImportsCache = new File(oldLocalPrefix + "imports/");
- if (oldImportsCache.exists() && oldImportsCache.isDirectory())
- deleteRecursively(oldImportsCache);
- }
-
- {
- File oldQmlCache = new File(oldLocalPrefix + "qml/");
- if (oldQmlCache.exists() && oldQmlCache.isDirectory())
- deleteRecursively(oldQmlCache);
- }
- }
- }
-
- private void startApp(final boolean firstStart)
- {
- try {
- if (m_activityInfo.metaData.containsKey("android.app.qt_sources_resource_id")) {
- int resourceId = m_activityInfo.metaData.getInt("android.app.qt_sources_resource_id");
- m_sources = getResources().getStringArray(resourceId);
- }
-
- if (m_activityInfo.metaData.containsKey("android.app.repository"))
- m_repository = m_activityInfo.metaData.getString("android.app.repository");
-
- if (m_activityInfo.metaData.containsKey("android.app.qt_libs_resource_id")) {
- int resourceId = m_activityInfo.metaData.getInt("android.app.qt_libs_resource_id");
- m_qtLibs = getResources().getStringArray(resourceId);
- }
-
- if (m_activityInfo.metaData.containsKey("android.app.use_local_qt_libs")
- && m_activityInfo.metaData.getInt("android.app.use_local_qt_libs") == 1) {
- ArrayList<String> libraryList = new ArrayList<String>();
-
-
- String localPrefix = "/data/local/tmp/qt/";
- if (m_activityInfo.metaData.containsKey("android.app.libs_prefix"))
- localPrefix = m_activityInfo.metaData.getString("android.app.libs_prefix");
-
- String pluginsPrefix = localPrefix;
-
- 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 + "/";
- pluginsPrefix = localPrefix + "qt-reserved-files/";
- cleanOldCacheIfNecessary(localPrefix, pluginsPrefix);
- extractBundledPluginsAndImports(pluginsPrefix);
- bundlingQtLibs = true;
- }
-
- if (m_qtLibs != null) {
- for (int i=0;i<m_qtLibs.length;i++) {
- libraryList.add(localPrefix
- + "lib/lib"
- + m_qtLibs[i]
- + ".so");
- }
- }
-
- if (m_activityInfo.metaData.containsKey("android.app.load_local_libs")) {
- String[] extraLibs = m_activityInfo.metaData.getString("android.app.load_local_libs").split(":");
- for (String lib : extraLibs) {
- if (lib.length() > 0) {
- if (lib.startsWith("lib/"))
- libraryList.add(localPrefix + lib);
- else
- libraryList.add(pluginsPrefix + lib);
- }
- }
- }
-
-
- String dexPaths = new String();
- String pathSeparator = System.getProperty("path.separator", ":");
- if (!bundlingQtLibs && m_activityInfo.metaData.containsKey("android.app.load_local_jars")) {
- String[] jarFiles = m_activityInfo.metaData.getString("android.app.load_local_jars").split(":");
- for (String jar:jarFiles) {
- if (jar.length() > 0) {
- if (dexPaths.length() > 0)
- dexPaths += pathSeparator;
- dexPaths += localPrefix + jar;
- }
- }
- }
-
- Bundle loaderParams = new Bundle();
- loaderParams.putInt(ERROR_CODE_KEY, 0);
- loaderParams.putString(DEX_PATH_KEY, dexPaths);
- loaderParams.putString(LOADER_CLASS_NAME_KEY, "org.qtproject.qt5.android.QtActivityDelegate");
- if (m_activityInfo.metaData.containsKey("android.app.static_init_classes")) {
- loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY,
- m_activityInfo.metaData.getString("android.app.static_init_classes").split(":"));
- }
- loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
-
-
- String themePath = getApplicationInfo().dataDir + "/qt-reserved-files/android-style/";
- String stylePath = themePath + m_displayDensity + "/";
- if (!(new File(stylePath)).exists())
- loaderParams.putString(EXTRACT_STYLE_KEY, stylePath);
- ENVIRONMENT_VARIABLES += "\tMINISTRO_ANDROID_STYLE_PATH=" + stylePath
- + "\tQT_ANDROID_THEMES_ROOT_PATH=" + themePath;
-
- loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES
- + "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml"
- + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports"
- + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins");
-
- if (APPLICATION_PARAMETERS != null) {
- loaderParams.putString(APPLICATION_PARAMETERS_KEY, APPLICATION_PARAMETERS);
- } else {
- Intent intent = getIntent();
- if (intent != null) {
- String parameters = intent.getStringExtra("applicationArguments");
- if (parameters != null)
- loaderParams.putString(APPLICATION_PARAMETERS_KEY, parameters.replace(' ', '\t'));
- }
- }
-
- loadApplication(loaderParams);
- return;
- }
-
- try {
- if (!bindService(new Intent(org.kde.necessitas.ministro.IMinistro.class.getCanonicalName()),
- m_ministroConnection,
- Context.BIND_AUTO_CREATE)) {
- throw new SecurityException("");
- }
- } catch (Exception e) {
- if (firstStart) {
- String msg = "This application requires Ministro service. Would you like to install it?";
- if (m_activityInfo.metaData.containsKey("android.app.ministro_needed_msg"))
- msg = m_activityInfo.metaData.getString("android.app.ministro_needed_msg");
- downloadUpgradeMinistro(msg);
- } else {
- ministroNotFound();
- }
- }
- } catch (Exception e) {
- Log.e(QtApplication.QtTAG, "Can't create main activity", e);
- }
- }
-
-
/////////////////////////// forward all notifications ////////////////////////////
/////////////////////////// Super class calls ////////////////////////////////////
@@ -749,8 +146,8 @@ public class QtActivity extends Activity
QtApplication.invokeDelegateMethod(QtApplication.onActivityResult, requestCode, resultCode, data);
return;
}
- if (requestCode == MINISTRO_INSTALL_REQUEST_CODE)
- startApp(false);
+ if (requestCode == QtLoader.MINISTRO_INSTALL_REQUEST_CODE)
+ m_loader.startApp(false);
super.onActivityResult(requestCode, resultCode, data);
}
public void super_onActivityResult(int requestCode, int resultCode, Intent data)
@@ -839,79 +236,7 @@ public class QtActivity extends Activity
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
- try {
- m_activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
- for (Field f : Class.forName("android.R$style").getDeclaredFields()) {
- if (f.getInt(null) == m_activityInfo.getThemeResource()) {
- QT_ANDROID_THEMES = new String[] {f.getName()};
- QT_ANDROID_DEFAULT_THEME = f.getName();
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- finish();
- return;
- }
-
- if (Build.VERSION.SDK_INT < 16) {
- // fatal error, show the error and quit
- AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create();
- if (m_activityInfo.metaData.containsKey("android.app.unsupported_android_version"))
- errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.unsupported_android_version"));
- else
- errorDialog.setMessage("Unsupported Android version.");
- errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- });
- errorDialog.show();
- return;
- }
-
- try {
- setTheme(Class.forName("android.R$style").getDeclaredField(QT_ANDROID_DEFAULT_THEME).getInt(null));
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- requestWindowFeature(Window.FEATURE_ACTION_BAR);
-
- if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null) {
- QtApplication.invokeDelegateMethod(QtApplication.onCreate, savedInstanceState);
- return;
- }
-
- m_displayDensity = getResources().getDisplayMetrics().densityDpi;
-
- ENVIRONMENT_VARIABLES += "\tQT_ANDROID_THEME=" + QT_ANDROID_DEFAULT_THEME
- + "/\tQT_ANDROID_THEME_DISPLAY_DPI=" + m_displayDensity + "\t";
-
- if (null == getLastNonConfigurationInstance()) {
- // if splash screen is defined, then show it
- // Note: QtActivityDelegate handles updating the splash screen
- // in onConfigurationChanged, change that too if you are changing
- // how the splash screen should be displayed
- if (m_activityInfo.metaData.containsKey("android.app.splash_screen_drawable"))
- getWindow().setBackgroundDrawableResource(m_activityInfo.metaData.getInt("android.app.splash_screen_drawable"));
- else
- getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
-
- if (m_activityInfo.metaData.containsKey("android.app.background_running")
- && m_activityInfo.metaData.getBoolean("android.app.background_running")) {
- ENVIRONMENT_VARIABLES += "QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED=0\t";
- } else {
- ENVIRONMENT_VARIABLES += "QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED=1\t";
- }
-
- if (m_activityInfo.metaData.containsKey("android.app.auto_screen_scale_factor")
- && m_activityInfo.metaData.getBoolean("android.app.auto_screen_scale_factor")) {
- ENVIRONMENT_VARIABLES += "QT_AUTO_SCREEN_SCALE_FACTOR=1\t";
- }
-
- startApp(true);
- }
+ m_loader.onCreate(savedInstanceState);
}
//---------------------------------------------------------------------------
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivityLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivityLoader.java
new file mode 100644
index 0000000000..836a7677b3
--- /dev/null
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivityLoader.java
@@ -0,0 +1,193 @@
+/*
+ Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt-project.org/legal
+
+ Commercial License Usage
+ Licensees holding valid commercial Qt licenses may use this file in
+ accordance with the commercial license agreement provided with the
+ Software or, alternatively, in accordance with the terms contained in
+ a written agreement between you and Digia. For licensing terms and
+ conditions see http://qt.digia.com/licensing. For further information
+ use the contact form at http://qt.digia.com/contact-us.
+
+ BSD License Usage
+ Alternatively, this file may be used under the BSD license as follows:
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.qtproject.qt5.android.bindings;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.Window;
+
+
+import java.lang.reflect.Field;
+
+public class QtActivityLoader extends QtLoader {
+ QtActivity m_activity;
+
+ QtActivityLoader(QtActivity activity)
+ {
+ super(activity);
+ m_activity = activity;
+ }
+ @Override
+ protected void downloadUpgradeMinistro(String msg) {
+ AlertDialog.Builder downloadDialog = new AlertDialog.Builder(m_activity);
+ downloadDialog.setMessage(msg);
+ downloadDialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ try {
+ Uri uri = Uri.parse("market://search?q=pname:org.kde.necessitas.ministro");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ m_activity.startActivityForResult(intent, MINISTRO_INSTALL_REQUEST_CODE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ ministroNotFound();
+ }
+ }
+ });
+
+ downloadDialog.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ m_activity.finish();
+ }
+ });
+ downloadDialog.show();
+ }
+
+ @Override
+ protected String loaderClassName() {
+ return "org.qtproject.qt5.android.QtActivityDelegate";
+ }
+
+ @Override
+ protected Class<?> contextClassName() {
+ return android.app.Activity.class;
+ }
+
+ @Override
+ protected void finish() {
+ m_activity.finish();
+ }
+
+ @Override
+ protected String getTitle() {
+ return (String) m_activity.getTitle();
+ }
+
+ @Override
+ protected void runOnUiThread(Runnable run) {
+ m_activity.runOnUiThread(run);
+ }
+
+ @Override
+ Intent getIntent() {
+ return m_activity.getIntent();
+ }
+
+ public void onCreate(Bundle savedInstanceState) {
+ try {
+ m_contextInfo = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), PackageManager.GET_META_DATA);
+ for (Field f : Class.forName("android.R$style").getDeclaredFields()) {
+ if (f.getInt(null) == ((ActivityInfo)m_contextInfo).getThemeResource()) {
+ QT_ANDROID_THEMES = new String[] {f.getName()};
+ QT_ANDROID_DEFAULT_THEME = f.getName();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ finish();
+ return;
+ }
+
+ if (Build.VERSION.SDK_INT < 16) {
+ // fatal error, show the error and quit
+ AlertDialog errorDialog = new AlertDialog.Builder(m_activity).create();
+ if (m_contextInfo.metaData.containsKey("android.app.unsupported_android_version"))
+ errorDialog.setMessage(m_contextInfo.metaData.getString("android.app.unsupported_android_version"));
+ else
+ errorDialog.setMessage("Unsupported Android version.");
+ errorDialog.setButton(m_activity.getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ errorDialog.show();
+ return;
+ }
+
+ try {
+ m_activity.setTheme(Class.forName("android.R$style").getDeclaredField(QT_ANDROID_DEFAULT_THEME).getInt(null));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ m_activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
+
+ if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null) {
+ QtApplication.invokeDelegateMethod(QtApplication.onCreate, savedInstanceState);
+ return;
+ }
+
+ m_displayDensity = m_activity.getResources().getDisplayMetrics().densityDpi;
+
+ ENVIRONMENT_VARIABLES += "\tQT_ANDROID_THEME=" + QT_ANDROID_DEFAULT_THEME
+ + "/\tQT_ANDROID_THEME_DISPLAY_DPI=" + m_displayDensity + "\t";
+
+ if (null == m_activity.getLastNonConfigurationInstance()) {
+ // if splash screen is defined, then show it
+ // Note: QtActivityDelegate handles updating the splash screen
+ // in onConfigurationChanged, change that too if you are changing
+ // how the splash screen should be displayed
+ if (m_contextInfo.metaData.containsKey("android.app.splash_screen_drawable"))
+ m_activity.getWindow().setBackgroundDrawableResource(m_contextInfo.metaData.getInt("android.app.splash_screen_drawable"));
+ else
+ m_activity.getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
+
+ if (m_contextInfo.metaData.containsKey("android.app.background_running")
+ && m_contextInfo.metaData.getBoolean("android.app.background_running")) {
+ ENVIRONMENT_VARIABLES += "QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED=0\t";
+ } else {
+ ENVIRONMENT_VARIABLES += "QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED=1\t";
+ }
+
+ if (m_contextInfo.metaData.containsKey("android.app.auto_screen_scale_factor")
+ && m_contextInfo.metaData.getBoolean("android.app.auto_screen_scale_factor")) {
+ ENVIRONMENT_VARIABLES += "QT_AUTO_SCREEN_SCALE_FACTOR=1\t";
+ }
+
+ startApp(true);
+ }
+ }
+}
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
index c78aeb7f13..2afede6d66 100644
--- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtApplication.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2013, BogDan Vatra <bogdan@kde.org>
+ Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
Contact: http://www.qt.io/licensing/
Commercial License Usage
@@ -36,13 +36,13 @@
package org.qtproject.qt5.android.bindings;
+import android.app.Application;
+
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
-import android.app.Application;
-
public class QtApplication extends Application
{
public final static String QtTAG = "Qt";
@@ -64,10 +64,11 @@ public class QtApplication extends Application
public static Method onKeyShortcut = null;
public static Method dispatchGenericMotionEvent = null;
public static Method onGenericMotionEvent = null;
-
- public static void setQtActivityDelegate(Object listener)
+ private static String activityClassName;
+ public static void setQtContextDelegate(Class<?> clazz, Object listener)
{
- QtApplication.m_delegateObject = listener;
+ m_delegateObject = listener;
+ activityClassName = clazz.getCanonicalName();
ArrayList<Method> delegateMethods = new ArrayList<Method>();
for (Method m : listener.getClass().getMethods()) {
@@ -83,7 +84,7 @@ public class QtApplication extends Application
for (Method delegateMethod : delegateMethods) {
try {
- QtActivity.class.getDeclaredMethod(delegateMethod.getName(), delegateMethod.getParameterTypes());
+ clazz.getDeclaredMethod(delegateMethod.getName(), delegateMethod.getParameterTypes());
if (QtApplication.m_delegateMethods.containsKey(delegateMethod.getName())) {
QtApplication.m_delegateMethods.get(delegateMethod.getName()).add(delegateMethod);
} else {
@@ -126,7 +127,6 @@ public class QtApplication extends Application
return result;
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
if (-1 == stackDeep) {
- String activityClassName = QtActivity.class.getCanonicalName();
for (int it=0;it<elements.length;it++)
if (elements[it].getClassName().equals(activityClassName)) {
stackDeep = it;
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
new file mode 100644
index 0000000000..0963220b0d
--- /dev/null
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
@@ -0,0 +1,655 @@
+/*
+ Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt.io/licensing/
+
+ Commercial License Usage
+ Licensees holding valid commercial Qt licenses may use this file in
+ accordance with the commercial license agreement provided with the
+ Software or, alternatively, in accordance with the terms contained in
+ a written agreement between you and The Qt Company. For licensing terms
+ and conditions see http://www.qt.io/terms-conditions. For further
+ information use the contact form at http://www.qt.io/contact-us.
+
+ BSD License Usage
+ Alternatively, this file may be used under the BSD license as follows:
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.qtproject.qt5.android.bindings;
+
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageInfo;
+import android.content.res.AssetManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import org.kde.necessitas.ministro.IMinistro;
+import org.kde.necessitas.ministro.IMinistroCallback;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import dalvik.system.DexClassLoader;
+
+public abstract class QtLoader {
+
+ public final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro instalation is finished
+ public static final int MINISTRO_API_LEVEL = 5; // Ministro api level (check IMinistro.aidl file)
+ public static final int NECESSITAS_API_LEVEL = 2; // Necessitas api level used by platform plugin
+ public static final int QT_VERSION = 0x050100; // This app requires at least Qt version 5.1.0
+
+ public static final String ERROR_CODE_KEY = "error.code";
+ public static final String ERROR_MESSAGE_KEY = "error.message";
+ public static final String DEX_PATH_KEY = "dex.path";
+ public static final String LIB_PATH_KEY = "lib.path";
+ public static final String LOADER_CLASS_NAME_KEY = "loader.class.name";
+ public static final String NATIVE_LIBRARIES_KEY = "native.libraries";
+ public static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
+ public static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
+ public static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
+ public static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id";
+ public static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id";
+ public static final String MAIN_LIBRARY_KEY = "main.library";
+ public static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
+ public static final String NECESSITAS_API_LEVEL_KEY = "necessitas.api.level";
+ public static final String EXTRACT_STYLE_KEY = "extract.android.style";
+
+ /// Ministro server parameter keys
+ public static final String REQUIRED_MODULES_KEY = "required.modules";
+ public static final String APPLICATION_TITLE_KEY = "application.title";
+ public static final String MINIMUM_MINISTRO_API_KEY = "minimum.ministro.api";
+ public static final String MINIMUM_QT_VERSION_KEY = "minimum.qt.version";
+ public static final String SOURCES_KEY = "sources"; // needs MINISTRO_API_LEVEL >=3 !!!
+ // Use this key to specify any 3rd party sources urls
+ // Ministro will download these repositories into their
+ // own folders, check http://community.kde.org/Necessitas/Ministro
+ // for more details.
+
+ public static final String REPOSITORY_KEY = "repository"; // use this key to overwrite the default ministro repsitory
+ public static final String ANDROID_THEMES_KEY = "android.themes"; // themes that your application uses
+
+
+ public String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application,
+ // the parameters must not contain any white spaces
+ // and must be separated with "\t"
+ // e.g "-param1\t-param2=value2\t-param3\tvalue3"
+
+ public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_STYLE=1\tQT_USE_ANDROID_NATIVE_DIALOGS=1\t";
+ // use this variable to add any environment variables to your application.
+ // the env vars must be separated with "\t"
+ // e.g. "ENV_VAR1=1\tENV_VAR2=2\t"
+ // Currently the following vars are used by the android plugin:
+ // * QT_USE_ANDROID_NATIVE_STYLE - 1 to use the android widget style if available.
+ // * QT_USE_ANDROID_NATIVE_DIALOGS -1 to use the android native dialogs.
+
+ public String[] QT_ANDROID_THEMES = null; // A list with all themes that your application want to use.
+ // The name of the theme must be the same with any theme from
+ // http://developer.android.com/reference/android/R.style.html
+ // The most used themes are:
+ // * "Theme" - (fallback) check http://developer.android.com/reference/android/R.style.html#Theme
+ // * "Theme_Black" - check http://developer.android.com/reference/android/R.style.html#Theme_Black
+ // * "Theme_Light" - (default for API <=10) check http://developer.android.com/reference/android/R.style.html#Theme_Light
+ // * "Theme_Holo" - check http://developer.android.com/reference/android/R.style.html#Theme_Holo
+ // * "Theme_Holo_Light" - (default for API 11-13) check http://developer.android.com/reference/android/R.style.html#Theme_Holo_Light
+ // * "Theme_DeviceDefault" - check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault
+ // * "Theme_DeviceDefault_Light" - (default for API 14+) check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault_Light
+
+ public String QT_ANDROID_DEFAULT_THEME = null; // sets the default theme.
+
+ public static final int INCOMPATIBLE_MINISTRO_VERSION = 1; // Incompatible Ministro version. Ministro needs to be upgraded.
+ public static final int BUFFER_SIZE = 1024;
+
+ public String[] m_sources = {"https://download.qt-project.org/ministro/android/qt5/qt-5.7"}; // Make sure you are using ONLY secure locations
+ public String m_repository = "default"; // Overwrites the default Ministro repository
+ // Possible values:
+ // * default - Ministro default repository set with "Ministro configuration tool".
+ // By default the stable version is used. Only this or stable repositories should
+ // be used in production.
+ // * stable - stable repository, only this and default repositories should be used
+ // in production.
+ // * testing - testing repository, DO NOT use this repository in production,
+ // this repository is used to push a new release, and should be used to test your application.
+ // * unstable - unstable repository, DO NOT use this repository in production,
+ // this repository is used to push Qt snapshots.
+ public String[] m_qtLibs = null; // required qt libs
+ public int m_displayDensity = -1;
+ private ContextWrapper m_context;
+ protected ComponentInfo m_contextInfo;
+
+ QtLoader(ContextWrapper context) {
+ m_context = context;
+ }
+
+ // Implement in subclass
+ protected void finish() {}
+
+ protected String getTitle() {
+ return "Qt";
+ }
+
+ protected void runOnUiThread(Runnable run) {
+ run.run();
+ }
+ protected void downloadUpgradeMinistro(String msg)
+ {
+ Log.e(QtApplication.QtTAG, msg);
+ }
+
+ protected abstract String loaderClassName();
+ protected abstract Class<?> contextClassName();
+
+ Intent getIntent()
+ {
+ return null;
+ }
+ // Implement in subclass
+
+
+ // this function is used to load and start the loader
+ private void loadApplication(Bundle loaderParams)
+ {
+ try {
+ final int errorCode = loaderParams.getInt(ERROR_CODE_KEY);
+ if (errorCode != 0) {
+ if (errorCode == INCOMPATIBLE_MINISTRO_VERSION) {
+ downloadUpgradeMinistro(loaderParams.getString(ERROR_MESSAGE_KEY));
+ return;
+ }
+
+ // fatal error, show the error and quit
+ AlertDialog errorDialog = new AlertDialog.Builder(m_context).create();
+ errorDialog.setMessage(loaderParams.getString(ERROR_MESSAGE_KEY));
+ errorDialog.setButton(m_context.getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ errorDialog.show();
+ return;
+ }
+
+ // add all bundled Qt libs to loader params
+ ArrayList<String> libs = new ArrayList<String>();
+ if ( m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id") )
+ libs.addAll(Arrays.asList(m_context.getResources().getStringArray(m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id"))));
+
+ String libName = null;
+ if ( m_contextInfo.metaData.containsKey("android.app.lib_name") ) {
+ libName = m_contextInfo.metaData.getString("android.app.lib_name");
+ loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function
+ }
+
+ loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs);
+ loaderParams.putInt(NECESSITAS_API_LEVEL_KEY, NECESSITAS_API_LEVEL);
+
+ // load and start QtLoader class
+ DexClassLoader classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files
+ m_context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written.
+ loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists)
+ m_context.getClassLoader()); // parent loader
+
+ Class<?> loaderClass = classLoader.loadClass(loaderParams.getString(LOADER_CLASS_NAME_KEY)); // load QtLoader class
+ Object qtLoader = loaderClass.newInstance(); // create an instance
+ Method prepareAppMethod = qtLoader.getClass().getMethod("loadApplication",
+ contextClassName(),
+ ClassLoader.class,
+ Bundle.class);
+ if (!(Boolean)prepareAppMethod.invoke(qtLoader, m_context, classLoader, loaderParams))
+ throw new Exception("");
+
+ QtApplication.setQtContextDelegate(m_context.getClass(), qtLoader);
+
+ // now load the application library so it's accessible from this class loader
+ if (libName != null)
+ System.loadLibrary(libName);
+
+ Method startAppMethod=qtLoader.getClass().getMethod("startApplication");
+ if (!(Boolean)startAppMethod.invoke(qtLoader))
+ throw new Exception("");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ AlertDialog errorDialog = new AlertDialog.Builder(m_context).create();
+ if (m_contextInfo.metaData.containsKey("android.app.fatal_error_msg"))
+ errorDialog.setMessage(m_contextInfo.metaData.getString("android.app.fatal_error_msg"));
+ else
+ errorDialog.setMessage("Fatal error, your application can't be started.");
+
+ errorDialog.setButton(m_context.getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ errorDialog.show();
+ }
+ }
+
+ private ServiceConnection m_ministroConnection=new ServiceConnection() {
+ private IMinistro m_service = null;
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service)
+ {
+ m_service = IMinistro.Stub.asInterface(service);
+ try {
+ if (m_service != null) {
+ Bundle parameters = new Bundle();
+ parameters.putStringArray(REQUIRED_MODULES_KEY, m_qtLibs);
+ parameters.putString(APPLICATION_TITLE_KEY, getTitle());
+ parameters.putInt(MINIMUM_MINISTRO_API_KEY, MINISTRO_API_LEVEL);
+ parameters.putInt(MINIMUM_QT_VERSION_KEY, QT_VERSION);
+ parameters.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES);
+ if (APPLICATION_PARAMETERS != null)
+ parameters.putString(APPLICATION_PARAMETERS_KEY, APPLICATION_PARAMETERS);
+ parameters.putStringArray(SOURCES_KEY, m_sources);
+ parameters.putString(REPOSITORY_KEY, m_repository);
+ if (QT_ANDROID_THEMES != null)
+ parameters.putStringArray(ANDROID_THEMES_KEY, QT_ANDROID_THEMES);
+ m_service.requestLoader(m_ministroCallback, parameters);
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private IMinistroCallback m_ministroCallback = new IMinistroCallback.Stub() {
+ // this function is called back by Ministro.
+ @Override
+ public void loaderReady(final Bundle loaderParams) throws RemoteException {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ m_context.unbindService(m_ministroConnection);
+ loadApplication(loaderParams);
+ }
+ });
+ }
+ };
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ m_service = null;
+ }
+ };
+
+ protected void ministroNotFound()
+ {
+ AlertDialog errorDialog = new AlertDialog.Builder(m_context).create();
+
+ if (m_contextInfo.metaData.containsKey("android.app.ministro_not_found_msg"))
+ errorDialog.setMessage(m_contextInfo.metaData.getString("android.app.ministro_not_found_msg"));
+ else
+ errorDialog.setMessage("Can't find Ministro service.\nThe application can't start.");
+
+ errorDialog.setButton(m_context.getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ 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 = m_context.getAssets();
+ InputStream inputStream = assetsManager.open(source);
+ OutputStream outputStream = new FileOutputStream(destinationFile);
+ copyFile(inputStream, outputStream);
+
+ inputStream.close();
+ outputStream.close();
+ }
+
+ 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);
+
+ inputStream.close();
+ outputStream.close();
+ }
+
+ private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion)
+ {
+ File versionFile = new File(pluginsPrefix + "cache.version");
+
+ long cacheVersion = 0;
+ if (versionFile.exists() && versionFile.canRead()) {
+ try {
+ DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile));
+ cacheVersion = inputStream.readLong();
+ inputStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (cacheVersion != packageVersion) {
+ deleteRecursively(new File(pluginsPrefix));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void extractBundledPluginsAndImports(String pluginsPrefix)
+ throws IOException
+ {
+ ArrayList<String> libs = new ArrayList<String>();
+
+ String libsDir = m_context.getApplicationInfo().nativeLibraryDir + "/";
+
+ long packageVersion = -1;
+ try {
+ PackageInfo packageInfo = m_context.getPackageManager().getPackageInfo(m_context.getPackageName(), 0);
+ packageVersion = packageInfo.lastUpdateTime;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion))
+ return;
+
+ {
+ File versionFile = new File(pluginsPrefix + "cache.version");
+
+ File parentDirectory = versionFile.getParentFile();
+ if (!parentDirectory.exists())
+ parentDirectory.mkdirs();
+
+ versionFile.createNewFile();
+
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile));
+ outputStream.writeLong(packageVersion);
+ outputStream.close();
+ }
+
+ {
+ String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
+ java.util.Set<String> keys = m_contextInfo.metaData.keySet();
+ if (m_contextInfo.metaData.containsKey(key)) {
+ String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key));
+
+ for (String bundledImportBinary : list) {
+ String[] split = bundledImportBinary.split(":");
+ String sourceFileName = libsDir + split[0];
+ String destinationFileName = pluginsPrefix + split[1];
+ createBundledBinary(sourceFileName, destinationFileName);
+ }
+ }
+ }
+
+ {
+ String key = BUNDLED_IN_ASSETS_RESOURCE_ID_KEY;
+ if (m_contextInfo.metaData.containsKey(key)) {
+ String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key));
+
+ for (String fileName : list) {
+ String[] split = fileName.split(":");
+ String sourceFileName = split[0];
+ String destinationFileName = pluginsPrefix + split[1];
+ copyAsset(sourceFileName, destinationFileName);
+ }
+ }
+
+ }
+ }
+
+ private void deleteRecursively(File directory)
+ {
+ File[] files = directory.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory())
+ deleteRecursively(file);
+ else
+ file.delete();
+ }
+
+ directory.delete();
+ }
+ }
+
+ private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix)
+ {
+ File newCache = new File(localPrefix);
+ if (!newCache.exists()) {
+ {
+ File oldPluginsCache = new File(oldLocalPrefix + "plugins/");
+ if (oldPluginsCache.exists() && oldPluginsCache.isDirectory())
+ deleteRecursively(oldPluginsCache);
+ }
+
+ {
+ File oldImportsCache = new File(oldLocalPrefix + "imports/");
+ if (oldImportsCache.exists() && oldImportsCache.isDirectory())
+ deleteRecursively(oldImportsCache);
+ }
+
+ {
+ File oldQmlCache = new File(oldLocalPrefix + "qml/");
+ if (oldQmlCache.exists() && oldQmlCache.isDirectory())
+ deleteRecursively(oldQmlCache);
+ }
+ }
+ }
+
+ public void startApp(final boolean firstStart)
+ {
+ try {
+ if (m_contextInfo.metaData.containsKey("android.app.qt_sources_resource_id")) {
+ int resourceId = m_contextInfo.metaData.getInt("android.app.qt_sources_resource_id");
+ m_sources = m_context.getResources().getStringArray(resourceId);
+ }
+
+ if (m_contextInfo.metaData.containsKey("android.app.repository"))
+ m_repository = m_contextInfo.metaData.getString("android.app.repository");
+
+ if (m_contextInfo.metaData.containsKey("android.app.qt_libs_resource_id")) {
+ int resourceId = m_contextInfo.metaData.getInt("android.app.qt_libs_resource_id");
+ m_qtLibs = m_context.getResources().getStringArray(resourceId);
+ }
+
+ if (m_contextInfo.metaData.containsKey("android.app.use_local_qt_libs")
+ && m_contextInfo.metaData.getInt("android.app.use_local_qt_libs") == 1) {
+ ArrayList<String> libraryList = new ArrayList<String>();
+
+
+ String localPrefix = "/data/local/tmp/qt/";
+ if (m_contextInfo.metaData.containsKey("android.app.libs_prefix"))
+ localPrefix = m_contextInfo.metaData.getString("android.app.libs_prefix");
+
+ String pluginsPrefix = localPrefix;
+
+ boolean bundlingQtLibs = false;
+ if (m_contextInfo.metaData.containsKey("android.app.bundle_local_qt_libs")
+ && m_contextInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) {
+ localPrefix = m_context.getApplicationInfo().dataDir + "/";
+ pluginsPrefix = localPrefix + "qt-reserved-files/";
+ cleanOldCacheIfNecessary(localPrefix, pluginsPrefix);
+ extractBundledPluginsAndImports(pluginsPrefix);
+ bundlingQtLibs = true;
+ }
+
+ if (m_qtLibs != null) {
+ for (int i=0;i<m_qtLibs.length;i++) {
+ libraryList.add(localPrefix
+ + "lib/lib"
+ + m_qtLibs[i]
+ + ".so");
+ }
+ }
+
+ if (m_contextInfo.metaData.containsKey("android.app.load_local_libs")) {
+ String[] extraLibs = m_contextInfo.metaData.getString("android.app.load_local_libs").split(":");
+ for (String lib : extraLibs) {
+ if (lib.length() > 0) {
+ if (lib.startsWith("lib/"))
+ libraryList.add(localPrefix + lib);
+ else
+ libraryList.add(pluginsPrefix + lib);
+ }
+ }
+ }
+
+
+ String dexPaths = new String();
+ String pathSeparator = System.getProperty("path.separator", ":");
+ if (!bundlingQtLibs && m_contextInfo.metaData.containsKey("android.app.load_local_jars")) {
+ String[] jarFiles = m_contextInfo.metaData.getString("android.app.load_local_jars").split(":");
+ for (String jar:jarFiles) {
+ if (jar.length() > 0) {
+ if (dexPaths.length() > 0)
+ dexPaths += pathSeparator;
+ dexPaths += localPrefix + jar;
+ }
+ }
+ }
+
+ Bundle loaderParams = new Bundle();
+ loaderParams.putInt(ERROR_CODE_KEY, 0);
+ loaderParams.putString(DEX_PATH_KEY, dexPaths);
+ loaderParams.putString(LOADER_CLASS_NAME_KEY, loaderClassName());
+ if (m_contextInfo.metaData.containsKey("android.app.static_init_classes")) {
+ loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY,
+ m_contextInfo.metaData.getString("android.app.static_init_classes").split(":"));
+ }
+ loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
+
+
+ String themePath = m_context.getApplicationInfo().dataDir + "/qt-reserved-files/android-style/";
+ String stylePath = themePath + m_displayDensity + "/";
+ if (!(new File(stylePath)).exists())
+ loaderParams.putString(EXTRACT_STYLE_KEY, stylePath);
+ ENVIRONMENT_VARIABLES += "\tMINISTRO_ANDROID_STYLE_PATH=" + stylePath
+ + "\tQT_ANDROID_THEMES_ROOT_PATH=" + themePath;
+
+ loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES
+ + "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml"
+ + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports"
+ + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins");
+
+ String appParams = null;
+ if (APPLICATION_PARAMETERS != null)
+ appParams = APPLICATION_PARAMETERS;
+
+ Intent intent = getIntent();
+ if (intent != null) {
+ String parameters = intent.getStringExtra("applicationArguments");
+ if (parameters != null)
+ if (appParams == null)
+ appParams = parameters;
+ else
+ appParams += '\t' + parameters;
+ }
+
+ if (m_contextInfo.metaData.containsKey("android.app.arguments")) {
+ String parameters = m_contextInfo.metaData.getString("android.app.arguments");
+ if (appParams == null)
+ appParams = parameters;
+ else
+ appParams += '\t' + parameters;
+ }
+
+ if (appParams != null)
+ loaderParams.putString(APPLICATION_PARAMETERS_KEY, appParams.replace(' ', '\t').trim());
+
+ loadApplication(loaderParams);
+ return;
+ }
+
+ try {
+ if (!m_context.bindService(new Intent(org.kde.necessitas.ministro.IMinistro.class.getCanonicalName()),
+ m_ministroConnection,
+ Context.BIND_AUTO_CREATE)) {
+ throw new SecurityException("");
+ }
+ } catch (Exception e) {
+ if (firstStart) {
+ String msg = "This application requires Ministro service. Would you like to install it?";
+ if (m_contextInfo.metaData.containsKey("android.app.ministro_needed_msg"))
+ msg = m_contextInfo.metaData.getString("android.app.ministro_needed_msg");
+ downloadUpgradeMinistro(msg);
+ } else {
+ ministroNotFound();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(QtApplication.QtTAG, "Can't create main activity", e);
+ }
+ }
+}
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtService.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtService.java
new file mode 100644
index 0000000000..c84bdd63c3
--- /dev/null
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtService.java
@@ -0,0 +1,153 @@
+/*
+ Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt.io/licensing/
+
+ Commercial License Usage
+ Licensees holding valid commercial Qt licenses may use this file in
+ accordance with the commercial license agreement provided with the
+ Software or, alternatively, in accordance with the terms contained in
+ a written agreement between you and The Qt Company. For licensing terms
+ and conditions see http://www.qt.io/terms-conditions. For further
+ information use the contact form at http://www.qt.io/contact-us.
+
+ BSD License Usage
+ Alternatively, this file may be used under the BSD license as follows:
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.qtproject.qt5.android.bindings;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.IBinder;
+
+public class QtService extends Service
+{
+ QtServiceLoader m_loader = new QtServiceLoader(this);
+
+
+ /////////////////////////// forward all notifications ////////////////////////////
+ /////////////////////////// Super class calls ////////////////////////////////////
+ /////////////// PLEASE DO NOT CHANGE THE FOLLOWING CODE //////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void onCreate()
+ {
+ super.onCreate();
+ m_loader.onCreate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+ QtApplication.invokeDelegate();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public IBinder onBind(Intent intent)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(intent);
+ if (res.invoked)
+ return (IBinder)res.methodReturns;
+ else
+ return null;
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig)
+ {
+ if (!QtApplication.invokeDelegate(newConfig).invoked)
+ super.onConfigurationChanged(newConfig);
+ }
+ public void super_onConfigurationChanged(Configuration newConfig)
+ {
+ super.onConfigurationChanged(newConfig);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onLowMemory()
+ {
+ if (!QtApplication.invokeDelegate().invoked)
+ super.onLowMemory();
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(intent, flags, startId);
+ if (res.invoked)
+ return (int) res.methodReturns;
+ else
+ return super.onStartCommand(intent, flags, startId);
+ }
+ public int super_onStartCommand(Intent intent, int flags, int startId)
+ {
+ return super.onStartCommand(intent, flags, startId);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onTaskRemoved(Intent rootIntent)
+ {
+ if (!QtApplication.invokeDelegate(rootIntent).invoked)
+ super.onTaskRemoved(rootIntent);
+ }
+ public void super_onTaskRemoved(Intent rootIntent)
+ {
+ super.onTaskRemoved(rootIntent);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public void onTrimMemory(int level)
+ {
+ if (!QtApplication.invokeDelegate(level).invoked)
+ super.onTrimMemory(level);
+ }
+ public void super_onTrimMemory(int level)
+ {
+ super.onTrimMemory(level);
+ }
+ //---------------------------------------------------------------------------
+
+ @Override
+ public boolean onUnbind(Intent intent)
+ {
+ QtApplication.InvokeResult res = QtApplication.invokeDelegate(intent);
+ if (res.invoked)
+ return (boolean) res.methodReturns;
+ else
+ return super.onUnbind(intent);
+ }
+ public boolean super_onUnbind(Intent intent)
+ {
+ return super.onUnbind(intent);
+ }
+ //---------------------------------------------------------------------------
+}
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtServiceLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtServiceLoader.java
new file mode 100644
index 0000000000..e64018f0a8
--- /dev/null
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtServiceLoader.java
@@ -0,0 +1,77 @@
+/*
+ Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
+ Contact: http://www.qt.io/licensing/
+
+ Commercial License Usage
+ Licensees holding valid commercial Qt licenses may use this file in
+ accordance with the commercial license agreement provided with the
+ Software or, alternatively, in accordance with the terms contained in
+ a written agreement between you and The Qt Company. For licensing terms
+ and conditions see http://www.qt.io/terms-conditions. For further
+ information use the contact form at http://www.qt.io/contact-us.
+
+ BSD License Usage
+ Alternatively, this file may be used under the BSD license as follows:
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.qtproject.qt5.android.bindings;
+
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+
+public class QtServiceLoader extends QtLoader {
+ QtService m_service;
+ QtServiceLoader(QtService service) {
+ super(service);
+ m_service = service;
+ }
+
+ public void onCreate() {
+ try {
+ m_contextInfo = m_service.getPackageManager().getServiceInfo(new ComponentName(m_service, m_service.getClass()), PackageManager.GET_META_DATA);
+ } catch (Exception e) {
+ e.printStackTrace();
+ m_service.stopSelf();
+ return;
+ }
+
+ if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null)
+ QtApplication.invokeDelegateMethod(QtApplication.onCreate);
+ startApp(true);
+ }
+
+ @Override
+ protected void finish() {
+ m_service.stopSelf();
+ }
+
+ @Override
+ protected String loaderClassName() {
+ return "org.qtproject.qt5.android.QtServiceDelegate";
+ }
+
+ @Override
+ protected Class<?> contextClassName() {
+ return android.app.Service.class;
+ }
+}
diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml
index 2a6d0b6fa3..02fd0ce23b 100644
--- a/src/android/templates/AndroidManifest.xml
+++ b/src/android/templates/AndroidManifest.xml
@@ -10,6 +10,11 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
+
+ <!-- Application arguments -->
+ <!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
+ <!-- Application arguments -->
+
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
@@ -32,9 +37,7 @@
<!-- Messages maps -->
<!-- Splash screen -->
- <!--
- <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
- -->
+ <!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
<!-- Splash screen -->
<!-- Background running -->
@@ -49,7 +52,53 @@
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
<!-- auto screen scale factor -->
</activity>
+
+ <!--service android:process=":qt" android:name="org.qtproject.qt5.android.bindings.QtService"-->
+ <!-- android:process=":qt" is needed to force the service to run on a separate process than the Activity -->
+
+ <!-- Application arguments -->
+ <!-- meta-data android:name="android.app.arguments" android:value="-service"/ -->
+ <!-- Application arguments -->
+ <!-- If you're using the same application (.so file) for activity and also for service, then you
+ need to use *android.app.arguments* to pass some arguments to your service in order to know which
+ one is which
+ -->
+
+ <!-- Ministro -->
+ <!-- meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
+ <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
+ <meta-data android:name="android.app.repository" android:value="default"/>
+ <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
+ <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/ -->
+ <!-- Ministro -->
+
+ <!-- Deploy Qt libs as part of package -->
+ <!-- meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
+ <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
+ <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/ -->
+ <!-- Deploy Qt libs as part of package -->
+
+ <!-- Run with local libs -->
+ <!-- meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
+ <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
+ <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
+ <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
+ <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/ -->
+ <!-- Run with local libs -->
+
+ <!-- Messages maps -->
+ <!-- meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
+ <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
+ <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/ -->
+ <!-- Messages maps -->
+
+
+ <!-- Background running -->
+ <!-- meta-data android:name="android.app.background_running" android:value="true"/ -->
+ <!-- Background running -->
+ <!--/service -->
</application>
+
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index e4fa0f7391..3ea121fcc2 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -925,17 +925,17 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\relates <QtGlobal>
\since 5.7
- qOverload() returns a pointer to an overloaded function. The template
+ Returns a pointer to an overloaded function. The template
parameter is the list of the argument types of the function.
\a functionPointer is the pointer to the (member) function:
\snippet code/src_corelib_global_qglobal.cpp 52
- If a member function is also const-overladed \l qConstOverload and
- \l qNonConstOverload needs to be used.
+ If a member function is also const-overloaded \l qConstOverload and
+ \l qNonConstOverload need to be used.
- qOverload() needs C++14 enabled. In C++11 only code the helper
- classes QOverload, QConstOverload, and QNonConstOverload could be used directly:
+ qOverload() requires C++14 enabled. In C++11-only code, the helper
+ classes QOverload, QConstOverload, and QNonConstOverload can be used directly:
\snippet code/src_corelib_global_qglobal.cpp 53
@@ -946,7 +946,7 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\relates <QtGlobal>
\since 5.7
- qConstOverload() returns a pointer to an constant member function:
+ Returns a pointer to a constant member function:
\snippet code/src_corelib_global_qglobal.cpp 54
@@ -957,7 +957,7 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\relates <QtGlobal>
\since 5.7
- qNonConstOverload() eturns a pointer to an non constant member function:
+ Returns a pointer to a non-constant member function:
\snippet code/src_corelib_global_qglobal.cpp 54
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 25973a3ae4..b6d8e6fdc8 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -506,6 +506,7 @@ public:
AA_EnableHighDpiScaling = 20,
AA_DisableHighDpiScaling = 21,
AA_UseStyleSheetPropagationInWidgetStyles = 22, // ### Qt 6: remove me
+ AA_DontUseNativeDialogs = 23,
// Add new attributes before this line
AA_AttributeCount
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 1efcce393d..b17a1ab48b 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -230,6 +230,10 @@
\l{The Style Sheet Syntax#Inheritance}{The Style Sheet Syntax - Inheritance}
for more details. This value has been added in Qt 5.7.
+ \value AA_DontUseNativeDialogs All dialogs created while this attribute is
+ set to true won't use the native dialogs provided by the platform.
+ This value has been added in Qt 5.7.
+
The following values are obsolete:
\value AA_ImmediateWidgetCreation This attribute is no longer fully
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index 1b0db64815..2a44daf8b5 100644
--- a/src/corelib/io/qstandardpaths_android.cpp
+++ b/src/corelib/io/qstandardpaths_android.cpp
@@ -63,12 +63,15 @@ static QJNIObjectPrivate applicationContext()
if (appCtx.isValid())
return appCtx;
- QJNIObjectPrivate activity(QtAndroidPrivate::activity());
- if (!activity.isValid())
- return appCtx;
+ QJNIObjectPrivate context(QtAndroidPrivate::activity());
+ if (!context.isValid()) {
+ context = QtAndroidPrivate::service();
+ if (!context.isValid())
+ return appCtx;
+ }
- appCtx = activity.callObjectMethod("getApplicationContext",
- "()Landroid/content/Context;");
+ appCtx = context.callObjectMethod("getApplicationContext",
+ "()Landroid/content/Context;");
return appCtx;
}
@@ -137,10 +140,6 @@ static QString getExternalFilesDir(const char *directoryField = 0)
if (!path.isEmpty())
return path;
- QJNIObjectPrivate activity(QtAndroidPrivate::activity());
- if (!activity.isValid())
- return QString();
-
QJNIObjectPrivate appCtx = applicationContext();
if (!appCtx.isValid())
return QString();
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index 2324a615d5..f576ed0d1c 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE
static JavaVM *g_javaVM = Q_NULLPTR;
static jobject g_jActivity = Q_NULLPTR;
+static jobject g_jService = Q_NULLPTR;
static jobject g_jClassLoader = Q_NULLPTR;
static jint g_androidSdkVersion = 0;
static jclass g_jNativeClass = Q_NULLPTR;
@@ -239,6 +240,32 @@ static void setAndroidSdkVersion(JNIEnv *env)
g_androidSdkVersion = env->GetStaticIntField(androidVersionClass, androidSDKFieldID);
}
+static void setNativeActivity(JNIEnv *env, jclass, jobject activity)
+{
+ if (g_jActivity != 0)
+ env->DeleteGlobalRef(g_jActivity);
+
+ if (activity != 0) {
+ g_jActivity = env->NewGlobalRef(activity);
+ env->DeleteLocalRef(activity);
+ } else {
+ g_jActivity = 0;
+ }
+}
+
+static void setNativeService(JNIEnv *env, jclass, jobject service)
+{
+ if (g_jService != 0)
+ env->DeleteGlobalRef(g_jService);
+
+ if (service != 0) {
+ g_jService = env->NewGlobalRef(service);
+ env->DeleteLocalRef(service);
+ } else {
+ g_jService = 0;
+ }
+}
+
jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
{
jclass jQtNative = env->FindClass("org/qtproject/qt5/android/QtNative");
@@ -254,10 +281,21 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
return JNI_ERR;
jobject activity = env->CallStaticObjectMethod(jQtNative, activityMethodID);
+
+ if (exceptionCheck(env))
+ return JNI_ERR;
+
+ jmethodID serviceMethodID = env->GetStaticMethodID(jQtNative,
+ "service",
+ "()Landroid/app/Service;");
+
if (exceptionCheck(env))
return JNI_ERR;
+ jobject service = env->CallStaticObjectMethod(jQtNative, serviceMethodID);
+ if (exceptionCheck(env))
+ return JNI_ERR;
jmethodID classLoaderMethodID = env->GetStaticMethodID(jQtNative,
"classLoader",
@@ -274,14 +312,22 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
g_jClassLoader = env->NewGlobalRef(classLoader);
env->DeleteLocalRef(classLoader);
- g_jActivity = env->NewGlobalRef(activity);
- env->DeleteLocalRef(activity);
+ if (activity) {
+ g_jActivity = env->NewGlobalRef(activity);
+ env->DeleteLocalRef(activity);
+ }
+ if (service) {
+ g_jService = env->NewGlobalRef(service);
+ env->DeleteLocalRef(service);
+ }
g_javaVM = vm;
static const JNINativeMethod methods[] = {
{"runPendingCppRunnables", "()V", reinterpret_cast<void *>(runPendingCppRunnables)},
{"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
{"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
+ {"setNativeActivity", "(Landroid/app/Activity;)V", reinterpret_cast<void *>(setNativeActivity)},
+ {"setNativeService", "(Landroid/app/Service;)V", reinterpret_cast<void *>(setNativeService)}
};
const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK);
@@ -305,6 +351,11 @@ jobject QtAndroidPrivate::activity()
return g_jActivity;
}
+jobject QtAndroidPrivate::service()
+{
+ return g_jService;
+}
+
JavaVM *QtAndroidPrivate::javaVM()
{
return g_javaVM;
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index 1bffd26e08..34bdbf6c80 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -100,6 +100,7 @@ namespace QtAndroidPrivate
typedef std::function<void()> Runnable;
Q_CORE_EXPORT jobject activity();
+ Q_CORE_EXPORT jobject service();
Q_CORE_EXPORT JavaVM *javaVM();
Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env);
jobject classLoader();
diff --git a/src/corelib/mimetypes/qmimeglobpattern_p.h b/src/corelib/mimetypes/qmimeglobpattern_p.h
index 0088931b5c..7b4ecd2f6a 100644
--- a/src/corelib/mimetypes/qmimeglobpattern_p.h
+++ b/src/corelib/mimetypes/qmimeglobpattern_p.h
@@ -88,7 +88,14 @@ public:
m_pattern = m_pattern.toLower();
}
}
- ~QMimeGlobPattern() {}
+
+ void swap(QMimeGlobPattern &other) Q_DECL_NOTHROW
+ {
+ qSwap(m_pattern, other.m_pattern);
+ qSwap(m_mimeType, other.m_mimeType);
+ qSwap(m_weight, other.m_weight);
+ qSwap(m_caseSensitivity, other.m_caseSensitivity);
+ }
bool matchFileName(const QString &filename) const;
@@ -103,6 +110,7 @@ private:
int m_weight;
Qt::CaseSensitivity m_caseSensitivity;
};
+Q_DECLARE_SHARED(QMimeGlobPattern)
class QMimeGlobPatternList : public QList<QMimeGlobPattern>
{
diff --git a/src/corelib/mimetypes/qmimemagicrule.cpp b/src/corelib/mimetypes/qmimemagicrule.cpp
index 1b8acc0f6e..09473caa78 100644
--- a/src/corelib/mimetypes/qmimemagicrule.cpp
+++ b/src/corelib/mimetypes/qmimemagicrule.cpp
@@ -82,36 +82,17 @@ QByteArray QMimeMagicRule::typeName(QMimeMagicRule::Type theType)
return magicRuleTypes_string + magicRuleTypes_indices[theType];
}
-class QMimeMagicRulePrivate
-{
-public:
- bool operator==(const QMimeMagicRulePrivate &other) const;
-
- QMimeMagicRule::Type type;
- QByteArray value;
- int startPos;
- int endPos;
- QByteArray mask;
-
- QByteArray pattern;
- quint32 number;
- quint32 numberMask;
-
- typedef bool (*MatchFunction)(const QMimeMagicRulePrivate *d, const QByteArray &data);
- MatchFunction matchFunction;
-};
-
-bool QMimeMagicRulePrivate::operator==(const QMimeMagicRulePrivate &other) const
+bool QMimeMagicRule::operator==(const QMimeMagicRule &other) const
{
- return type == other.type &&
- value == other.value &&
- startPos == other.startPos &&
- endPos == other.endPos &&
- mask == other.mask &&
- pattern == other.pattern &&
- number == other.number &&
- numberMask == other.numberMask &&
- matchFunction == other.matchFunction;
+ return m_type == other.m_type &&
+ m_value == other.m_value &&
+ m_startPos == other.m_startPos &&
+ m_endPos == other.m_endPos &&
+ m_mask == other.m_mask &&
+ m_pattern == other.m_pattern &&
+ m_number == other.m_number &&
+ m_numberMask == other.m_numberMask &&
+ m_matchFunction == other.m_matchFunction;
}
// Used by both providers
@@ -164,23 +145,23 @@ bool QMimeMagicRule::matchSubstring(const char *dataPtr, int dataSize, int range
return true;
}
-static bool matchString(const QMimeMagicRulePrivate *d, const QByteArray &data)
+bool QMimeMagicRule::matchString(const QByteArray &data) const
{
- const int rangeLength = d->endPos - d->startPos + 1;
- return QMimeMagicRule::matchSubstring(data.constData(), data.size(), d->startPos, rangeLength, d->pattern.size(), d->pattern.constData(), d->mask.constData());
+ const int rangeLength = m_endPos - m_startPos + 1;
+ return QMimeMagicRule::matchSubstring(data.constData(), data.size(), m_startPos, rangeLength, m_pattern.size(), m_pattern.constData(), m_mask.constData());
}
template <typename T>
-static bool matchNumber(const QMimeMagicRulePrivate *d, const QByteArray &data)
+bool QMimeMagicRule::matchNumber(const QByteArray &data) const
{
- const T value(d->number);
- const T mask(d->numberMask);
+ const T value(m_number);
+ const T mask(m_numberMask);
- //qDebug() << "matchNumber" << "0x" << QString::number(d->number, 16) << "size" << sizeof(T);
- //qDebug() << "mask" << QString::number(d->numberMask, 16);
+ //qDebug() << "matchNumber" << "0x" << QString::number(m_number, 16) << "size" << sizeof(T);
+ //qDebug() << "mask" << QString::number(m_numberMask, 16);
- const char *p = data.constData() + d->startPos;
- const char *e = data.constData() + qMin(data.size() - int(sizeof(T)), d->endPos + 1);
+ const char *p = data.constData() + m_startPos;
+ const char *e = data.constData() + qMin(data.size() - int(sizeof(T)), m_endPos + 1);
for ( ; p <= e; ++p) {
if ((*reinterpret_cast<const T*>(p) & mask) == (value & mask))
return true;
@@ -242,105 +223,102 @@ static inline QByteArray makePattern(const QByteArray &value)
// <match value="must be converted with BinHex" type="string" offset="11"/>
// <match value="0x9501" type="big16" offset="0:64"/>
-QMimeMagicRule::QMimeMagicRule(const QString &typeStr,
- const QByteArray &theValue,
+QMimeMagicRule::QMimeMagicRule(const QString &type,
+ const QByteArray &value,
const QString &offsets,
- const QByteArray &theMask,
- QString *errorString) :
- d(new QMimeMagicRulePrivate)
+ const QByteArray &mask,
+ QString *errorString)
+ : m_type(QMimeMagicRule::type(type.toLatin1())),
+ m_value(value),
+ m_mask(mask),
+ m_matchFunction(nullptr)
{
- d->value = theValue;
- d->mask = theMask;
- d->matchFunction = 0;
-
- d->type = QMimeMagicRule::type(typeStr.toLatin1());
- if (d->type == Invalid) {
- *errorString = QStringLiteral("Type %s is not supported").arg(typeStr);
- }
+ if (m_type == Invalid)
+ *errorString = QStringLiteral("Type %s is not supported").arg(type);
// Parse for offset as "1" or "1:10"
const int colonIndex = offsets.indexOf(QLatin1Char(':'));
const QString startPosStr = colonIndex == -1 ? offsets : offsets.mid(0, colonIndex);
const QString endPosStr = colonIndex == -1 ? offsets : offsets.mid(colonIndex + 1);
- if (!QMimeTypeParserBase::parseNumber(startPosStr, &d->startPos, errorString) ||
- !QMimeTypeParserBase::parseNumber(endPosStr, &d->endPos, errorString)) {
- d->type = Invalid;
+ if (!QMimeTypeParserBase::parseNumber(startPosStr, &m_startPos, errorString) ||
+ !QMimeTypeParserBase::parseNumber(endPosStr, &m_endPos, errorString)) {
+ m_type = Invalid;
return;
}
- if (d->value.isEmpty()) {
- d->type = Invalid;
+ if (m_value.isEmpty()) {
+ m_type = Invalid;
if (errorString)
*errorString = QLatin1String("Invalid empty magic rule value");
return;
}
- if (d->type >= Host16 && d->type <= Byte) {
+ if (m_type >= Host16 && m_type <= Byte) {
bool ok;
- d->number = d->value.toUInt(&ok, 0); // autodetect
+ m_number = m_value.toUInt(&ok, 0); // autodetect base
if (!ok) {
- d->type = Invalid;
+ m_type = Invalid;
if (errorString)
*errorString = QString::fromLatin1("Invalid magic rule value \"%1\"").arg(
- QString::fromLatin1(d->value));
+ QString::fromLatin1(m_value));
return;
}
- d->numberMask = !d->mask.isEmpty() ? d->mask.toUInt(&ok, 0) : 0; // autodetect
+ m_numberMask = !m_mask.isEmpty() ? m_mask.toUInt(&ok, 0) : 0; // autodetect base
}
- switch (d->type) {
+ switch (m_type) {
case String:
- d->pattern = makePattern(d->value);
- d->pattern.squeeze();
- if (!d->mask.isEmpty()) {
- if (d->mask.size() < 4 || !d->mask.startsWith("0x")) {
- d->type = Invalid;
+ m_pattern = makePattern(m_value);
+ m_pattern.squeeze();
+ if (!m_mask.isEmpty()) {
+ if (m_mask.size() < 4 || !m_mask.startsWith("0x")) {
+ m_type = Invalid;
if (errorString)
*errorString = QString::fromLatin1("Invalid magic rule mask \"%1\"").arg(
- QString::fromLatin1(d->mask));
+ QString::fromLatin1(m_mask));
return;
}
const QByteArray &tempMask = QByteArray::fromHex(QByteArray::fromRawData(
- d->mask.constData() + 2, d->mask.size() - 2));
- if (tempMask.size() != d->pattern.size()) {
- d->type = Invalid;
+ m_mask.constData() + 2, m_mask.size() - 2));
+ if (tempMask.size() != m_pattern.size()) {
+ m_type = Invalid;
if (errorString)
*errorString = QString::fromLatin1("Invalid magic rule mask size \"%1\"").arg(
- QString::fromLatin1(d->mask));
+ QString::fromLatin1(m_mask));
return;
}
- d->mask = tempMask;
+ m_mask = tempMask;
} else {
- d->mask.fill(char(-1), d->pattern.size());
+ m_mask.fill(char(-1), m_pattern.size());
}
- d->mask.squeeze();
- d->matchFunction = matchString;
+ m_mask.squeeze();
+ m_matchFunction = &QMimeMagicRule::matchString;
break;
case Byte:
- if (d->number <= quint8(-1)) {
- if (d->numberMask == 0)
- d->numberMask = quint8(-1);
- d->matchFunction = matchNumber<quint8>;
+ if (m_number <= quint8(-1)) {
+ if (m_numberMask == 0)
+ m_numberMask = quint8(-1);
+ m_matchFunction = &QMimeMagicRule::matchNumber<quint8>;
}
break;
case Big16:
case Host16:
case Little16:
- if (d->number <= quint16(-1)) {
- d->number = d->type == Little16 ? qFromLittleEndian<quint16>(d->number) : qFromBigEndian<quint16>(d->number);
- if (d->numberMask == 0)
- d->numberMask = quint16(-1);
- d->matchFunction = matchNumber<quint16>;
+ if (m_number <= quint16(-1)) {
+ m_number = m_type == Little16 ? qFromLittleEndian<quint16>(m_number) : qFromBigEndian<quint16>(m_number);
+ if (m_numberMask == 0)
+ m_numberMask = quint16(-1);
+ m_matchFunction = &QMimeMagicRule::matchNumber<quint16>;
}
break;
case Big32:
case Host32:
case Little32:
- if (d->number <= quint32(-1)) {
- d->number = d->type == Little32 ? qFromLittleEndian<quint32>(d->number) : qFromBigEndian<quint32>(d->number);
- if (d->numberMask == 0)
- d->numberMask = quint32(-1);
- d->matchFunction = matchNumber<quint32>;
+ if (m_number <= quint32(-1)) {
+ m_number = m_type == Little32 ? qFromLittleEndian<quint32>(m_number) : qFromBigEndian<quint32>(m_number);
+ if (m_numberMask == 0)
+ m_numberMask = quint32(-1);
+ m_matchFunction = &QMimeMagicRule::matchNumber<quint32>;
}
break;
default:
@@ -348,65 +326,19 @@ QMimeMagicRule::QMimeMagicRule(const QString &typeStr,
}
}
-QMimeMagicRule::QMimeMagicRule(const QMimeMagicRule &other) :
- d(new QMimeMagicRulePrivate(*other.d))
-{
-}
-
-QMimeMagicRule::~QMimeMagicRule()
-{
-}
-
-QMimeMagicRule &QMimeMagicRule::operator=(const QMimeMagicRule &other)
-{
- *d = *other.d;
- return *this;
-}
-
-bool QMimeMagicRule::operator==(const QMimeMagicRule &other) const
-{
- return d == other.d ||
- *d == *other.d;
-}
-
-QMimeMagicRule::Type QMimeMagicRule::type() const
-{
- return d->type;
-}
-
-QByteArray QMimeMagicRule::value() const
-{
- return d->value;
-}
-
-int QMimeMagicRule::startPos() const
-{
- return d->startPos;
-}
-
-int QMimeMagicRule::endPos() const
-{
- return d->endPos;
-}
-
QByteArray QMimeMagicRule::mask() const
{
- QByteArray result = d->mask;
- if (d->type == String) {
+ QByteArray result = m_mask;
+ if (m_type == String) {
// restore '0x'
result = "0x" + result.toHex();
}
return result;
}
-bool QMimeMagicRule::isValid() const
-{
- return d->matchFunction;
-}
-
bool QMimeMagicRule::matches(const QByteArray &data) const
{
- const bool ok = d->matchFunction && d->matchFunction(d.data(), data);
+ const bool ok = m_matchFunction && (this->*m_matchFunction)(data);
if (!ok)
return false;
diff --git a/src/corelib/mimetypes/qmimemagicrule_p.h b/src/corelib/mimetypes/qmimemagicrule_p.h
index 84c2fe2174..26f93d96cc 100644
--- a/src/corelib/mimetypes/qmimemagicrule_p.h
+++ b/src/corelib/mimetypes/qmimemagicrule_p.h
@@ -61,7 +61,6 @@
QT_BEGIN_NAMESPACE
-class QMimeMagicRulePrivate;
class QMimeMagicRule
{
public:
@@ -69,20 +68,29 @@ public:
QMimeMagicRule(const QString &typeStr, const QByteArray &value, const QString &offsets,
const QByteArray &mask, QString *errorString);
- QMimeMagicRule(const QMimeMagicRule &other);
- ~QMimeMagicRule();
- QMimeMagicRule &operator=(const QMimeMagicRule &other);
+ void swap(QMimeMagicRule &other) Q_DECL_NOTHROW
+ {
+ qSwap(m_type, other.m_type);
+ qSwap(m_value, other.m_value);
+ qSwap(m_startPos, other.m_startPos);
+ qSwap(m_endPos, other.m_endPos);
+ qSwap(m_mask, other.m_mask);
+ qSwap(m_pattern, other.m_pattern);
+ qSwap(m_number, other.m_number);
+ qSwap(m_numberMask, other.m_numberMask);
+ qSwap(m_matchFunction, other.m_matchFunction);
+ }
bool operator==(const QMimeMagicRule &other) const;
- Type type() const;
- QByteArray value() const;
- int startPos() const;
- int endPos() const;
+ Type type() const { return m_type; }
+ QByteArray value() const { return m_value; }
+ int startPos() const { return m_startPos; }
+ int endPos() const { return m_endPos; }
QByteArray mask() const;
- bool isValid() const;
+ bool isValid() const { return m_matchFunction != Q_NULLPTR; }
bool matches(const QByteArray &data) const;
@@ -94,9 +102,26 @@ public:
static bool matchSubstring(const char *dataPtr, int dataSize, int rangeStart, int rangeLength, int valueLength, const char *valueData, const char *mask);
private:
- const QScopedPointer<QMimeMagicRulePrivate> d;
+ Type m_type;
+ QByteArray m_value;
+ int m_startPos;
+ int m_endPos;
+ QByteArray m_mask;
+
+ QByteArray m_pattern;
+ quint32 m_number;
+ quint32 m_numberMask;
+
+ typedef bool (QMimeMagicRule::*MatchFunction)(const QByteArray &data) const;
+ MatchFunction m_matchFunction;
+
+private:
+ // match functions
+ bool matchString(const QByteArray &data) const;
+ template <typename T>
+ bool matchNumber(const QByteArray &data) const;
};
-Q_DECLARE_TYPEINFO(QMimeMagicRule, Q_MOVABLE_TYPE);
+Q_DECLARE_SHARED(QMimeMagicRule)
QT_END_NAMESPACE
diff --git a/src/corelib/mimetypes/qmimemagicrulematcher_p.h b/src/corelib/mimetypes/qmimemagicrulematcher_p.h
index b2e171ec1f..5e3d5306c0 100644
--- a/src/corelib/mimetypes/qmimemagicrulematcher_p.h
+++ b/src/corelib/mimetypes/qmimemagicrulematcher_p.h
@@ -66,6 +66,13 @@ class QMimeMagicRuleMatcher
public:
explicit QMimeMagicRuleMatcher(const QString &mime, unsigned priority = 65535);
+ void swap(QMimeMagicRuleMatcher &other) Q_DECL_NOTHROW
+ {
+ qSwap(m_list, other.m_list);
+ qSwap(m_priority, other.m_priority);
+ qSwap(m_mimetype, other.m_mimetype);
+ }
+
bool operator==(const QMimeMagicRuleMatcher &other) const;
void addRule(const QMimeMagicRule &rule);
@@ -83,6 +90,7 @@ private:
unsigned m_priority;
QString m_mimetype;
};
+Q_DECLARE_SHARED(QMimeMagicRuleMatcher)
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 69f8d72b47..48b94abae5 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -883,16 +883,12 @@ bool QThread::isInterruptionRequested() const
Note: don't try to deliver events from the started() signal.
*/
-static void setThreadDoesNotRequireCoreApplication()
-{
- QThreadData::current()->requiresCoreApplication = false;
-}
-
QDaemonThread::QDaemonThread(QObject *parent)
: QThread(parent)
{
// QThread::started() is emitted from the thread we start
- connect(this, &QThread::started, setThreadDoesNotRequireCoreApplication);
+ connect(this, &QThread::started,
+ [](){ QThreadData::current()->requiresCoreApplication = false; });
}
QDaemonThread::~QDaemonThread()
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index 280f9ea006..e794da8326 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -975,9 +975,11 @@ bool QDate::setDate(int year, int month, int day)
Returns 0 if the date is invalid.
+ \note In Qt versions prior to 5.7, this function is marked as non-\c{const}.
+
\sa year(), month(), day(), isValid()
*/
-void QDate::getDate(int *year, int *month, int *day)
+void QDate::getDate(int *year, int *month, int *day) const
{
ParsedDate pd = { 0, 0, 0 };
if (isValid())
@@ -991,6 +993,17 @@ void QDate::getDate(int *year, int *month, int *day)
*day = pd.day;
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+/*!
+ \overload
+ \internal
+*/
+void QDate::getDate(int *year, int *month, int *day)
+{
+ qAsConst(*this).getDate(year, month, day);
+}
+#endif // < Qt 6
+
/*!
Returns a QDate object containing a date \a ndays later than the
date of this object (or earlier if \a ndays is negative).
diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h
index af91ad0fe5..ee3be5553b 100644
--- a/src/corelib/tools/qdatetime.h
+++ b/src/corelib/tools/qdatetime.h
@@ -99,7 +99,10 @@ QT_DEPRECATED inline bool setYMD(int y, int m, int d)
bool setDate(int year, int month, int day);
- void getDate(int *year, int *month, int *day);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ void getDate(int *year, int *month, int *day); // ### Qt 6: remove
+#endif // < Qt 6
+ void getDate(int *year, int *month, int *day) const;
QDate addDays(qint64 days) const Q_REQUIRED_RESULT;
QDate addMonths(int months) const Q_REQUIRED_RESULT;
diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp
index 9ffef05d78..bbcd64d34f 100644
--- a/src/corelib/tools/qdatetimeparser.cpp
+++ b/src/corelib/tools/qdatetimeparser.cpp
@@ -131,13 +131,15 @@ bool QDateTimeParser::setDigit(QDateTime &v, int index, int newVal) const
}
const SectionNode &node = sectionNodes.at(index);
- int year = v.date().year();
- int month = v.date().month();
- int day = v.date().day();
- int hour = v.time().hour();
- int minute = v.time().minute();
- int second = v.time().second();
- int msec = v.time().msec();
+ const QDate date = v.date();
+ const QTime time = v.time();
+ int year = date.year();
+ int month = date.month();
+ int day = date.day();
+ int hour = time.hour();
+ int minute = time.minute();
+ int second = time.second();
+ int msec = time.msec();
switch (node.type) {
case Hour24Section: case Hour12Section: hour = newVal; break;
@@ -887,14 +889,16 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos
QDTPDEBUG << "parse" << input;
{
int year, month, day;
- currentValue.date().getDate(&year, &month, &day);
+ QDate currentDate = currentValue.date();
+ const QTime currentTime = currentValue.time();
+ currentDate.getDate(&year, &month, &day);
int year2digits = year % 100;
- int hour = currentValue.time().hour();
+ int hour = currentTime.hour();
int hour12 = -1;
- int minute = currentValue.time().minute();
- int second = currentValue.time().second();
- int msec = currentValue.time().msec();
- int dayofweek = currentValue.date().dayOfWeek();
+ int minute = currentTime.minute();
+ int second = currentTime.second();
+ int msec = currentTime.msec();
+ int dayofweek = currentDate.dayOfWeek();
int ampm = -1;
Sections isSet = NoSection;
@@ -1136,10 +1140,11 @@ end:
}
case MonthSection:
if (sn.count >= 3) {
- int tmp = newCurrentValue.date().month();
+ const int currentMonth = newCurrentValue.date().month();
+ int tmp = currentMonth;
// I know the first possible month makes the date too early
while ((tmp = findMonth(t, tmp + 1, i)) != -1) {
- const QDateTime copy(newCurrentValue.addMonths(tmp - newCurrentValue.date().month()));
+ const QDateTime copy(newCurrentValue.addMonths(tmp - currentMonth));
if (copy >= minimum && copy <= maximum)
break; // break out of while
}
@@ -1253,7 +1258,8 @@ int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionI
QLocale l = locale();
for (int month=startMonth; month<=12; ++month) {
- QString str2 = l.monthName(month, type).toLower();
+ const QString monthName = l.monthName(month, type);
+ QString str2 = monthName.toLower();
if (str1.startsWith(str2)) {
if (used) {
@@ -1261,7 +1267,7 @@ int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionI
*used = str2.size();
}
if (usedMonth)
- *usedMonth = l.monthName(month, type);
+ *usedMonth = monthName;
return month;
}
@@ -1286,7 +1292,7 @@ int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionI
if (used)
*used = limit;
if (usedMonth)
- *usedMonth = l.monthName(month, type);
+ *usedMonth = monthName;
return month;
}
}
@@ -1573,7 +1579,8 @@ bool QDateTimeParser::potentialValue(const QString &str, int min, int max, int i
int val = (int)locale().toUInt(str);
const SectionNode &sn = sectionNode(index);
if (sn.type == YearSection2Digits) {
- val += currentValue.date().year() - (currentValue.date().year() % 100);
+ const int year = currentValue.date().year();
+ val += year - (year % 100);
}
if (val >= min && val <= max && str.size() == size) {
return true;
diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp
index e843351cf7..479a4283b0 100644
--- a/src/gui/itemmodels/qstandarditemmodel.cpp
+++ b/src/gui/itemmodels/qstandarditemmodel.cpp
@@ -2168,6 +2168,7 @@ void QStandardItemModel::clear()
Q_D(QStandardItemModel);
beginResetModel();
d->root.reset(new QStandardItem);
+ d->root->setFlags(Qt::ItemIsDropEnabled);
d->root->d_func()->setModel(this);
qDeleteAll(d->columnHeaderItems);
d->columnHeaderItems.clear();
diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp
index 14c01085e7..5eb216d58e 100644
--- a/src/gui/kernel/qshortcutmap.cpp
+++ b/src/gui/kernel/qshortcutmap.cpp
@@ -191,7 +191,7 @@ int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &key
bool allIds = id == 0;
// Special case, remove everything
- if (allOwners && allKeys && id == 0) {
+ if (allOwners && allKeys && allIds) {
itemsRemoved = d->sequences.size();
d->sequences.clear();
return itemsRemoved;
diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp
index b295fe986a..e184fed275 100644
--- a/src/gui/kernel/qstylehints.cpp
+++ b/src/gui/kernel/qstylehints.cpp
@@ -76,6 +76,7 @@ public:
, m_startDragTime(-1)
, m_keyboardInputInterval(-1)
, m_cursorFlashTime(-1)
+ , m_tabFocusBehavior(-1)
{}
int m_mouseDoubleClickInterval;
@@ -84,6 +85,7 @@ public:
int m_startDragTime;
int m_keyboardInputInterval;
int m_cursorFlashTime;
+ int m_tabFocusBehavior;
};
/*!
@@ -416,7 +418,25 @@ bool QStyleHints::setFocusOnTouchRelease() const
Qt::TabFocusBehavior QStyleHints::tabFocusBehavior() const
{
- return Qt::TabFocusBehavior(themeableHint(QPlatformTheme::TabFocusBehavior, QPlatformIntegration::TabFocusBehavior).toInt());
+ Q_D(const QStyleHints);
+ return Qt::TabFocusBehavior(d->m_tabFocusBehavior >= 0 ?
+ d->m_tabFocusBehavior :
+ themeableHint(QPlatformTheme::TabFocusBehavior, QPlatformIntegration::TabFocusBehavior).toInt());
+}
+
+/*!
+ Sets the \a tabFocusBehavior.
+ \internal
+ \sa tabFocusBehavior()
+ \since 5.7
+*/
+void QStyleHints::setTabFocusBehavior(Qt::TabFocusBehavior tabFocusBehavior)
+{
+ Q_D(QStyleHints);
+ if (d->m_tabFocusBehavior == tabFocusBehavior)
+ return;
+ d->m_tabFocusBehavior = tabFocusBehavior;
+ emit tabFocusBehaviorChanged(tabFocusBehavior);
}
/*!
diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h
index a79fad805a..0b07e60579 100644
--- a/src/gui/kernel/qstylehints.h
+++ b/src/gui/kernel/qstylehints.h
@@ -67,7 +67,7 @@ class Q_GUI_EXPORT QStyleHints : public QObject
Q_PROPERTY(int startDragTime READ startDragTime NOTIFY startDragTimeChanged FINAL)
Q_PROPERTY(int startDragVelocity READ startDragVelocity STORED false CONSTANT FINAL)
Q_PROPERTY(bool useRtlExtensions READ useRtlExtensions STORED false CONSTANT FINAL)
- Q_PROPERTY(Qt::TabFocusBehavior tabFocusBehavior READ tabFocusBehavior STORED false CONSTANT FINAL)
+ Q_PROPERTY(Qt::TabFocusBehavior tabFocusBehavior READ tabFocusBehavior NOTIFY tabFocusBehaviorChanged FINAL)
Q_PROPERTY(bool singleClickActivation READ singleClickActivation STORED false CONSTANT FINAL)
public:
@@ -93,6 +93,7 @@ public:
bool useRtlExtensions() const;
bool setFocusOnTouchRelease() const;
Qt::TabFocusBehavior tabFocusBehavior() const;
+ void setTabFocusBehavior(Qt::TabFocusBehavior tabFocusBehavior);
bool singleClickActivation() const;
Q_SIGNALS:
@@ -102,6 +103,7 @@ Q_SIGNALS:
void mousePressAndHoldIntervalChanged(int mousePressAndHoldInterval);
void startDragDistanceChanged(int startDragDistance);
void startDragTimeChanged(int startDragTime);
+ void tabFocusBehaviorChanged(Qt::TabFocusBehavior tabFocusBehavior);
private:
friend class QGuiApplication;
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index 6110764094..5f5b7f46ec 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -1630,6 +1630,29 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
}
/*!
+ \enum QOpenGLFramebufferObject::FramebufferRestorePolicy
+ \since 5.7
+
+ This enum type is used to configure the behavior related to restoring
+ framebuffer bindings when calling blitFramebuffer().
+
+ \value DontRestoreFramebufferBinding Do not restore the previous framebuffer binding.
+ The caller is responsible for tracking and setting
+ the framebuffer binding as needed.
+
+ \value RestoreFramebufferBindingToDefault After the blit operation, bind the default
+ framebuffer.
+
+ \value RestoreFrameBufferBinding Restore the previously bound framebuffer. This is
+ potentially expensive because of the need to
+ query the currently bound framebuffer.
+
+ \sa blitFramebuffer()
+*/
+
+/*!
+ \since 5.7
+
Blits from the \a sourceRect rectangle in the \a source framebuffer
object to the \a targetRect rectangle in the \a target framebuffer object.
@@ -1661,6 +1684,13 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
drawColorAttachmentIndex specify the index of the color attachments in the
source and destination framebuffers.
+ The \a restorePolicy determines if the framebuffer that was bound prior to
+ calling this function should be restored, or if the default framebuffer
+ should be bound before returning, of if the caller is responsible for
+ tracking and setting the bound framebuffer. Restoring the previous
+ framebuffer can be relatively expensive due to the call to \c{glGetIntegerv}
+ which on some OpenGL drivers may imply a pipeline stall.
+
\sa hasOpenGLFramebufferBlit()
*/
void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
@@ -1668,7 +1698,8 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
GLbitfield buffers,
GLenum filter,
int readColorAttachmentIndex,
- int drawColorAttachmentIndex)
+ int drawColorAttachmentIndex,
+ QOpenGLFramebufferObject::FramebufferRestorePolicy restorePolicy)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!ctx)
@@ -1679,7 +1710,8 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
return;
GLuint prevFbo = 0;
- ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
+ if (restorePolicy == RestoreFrameBufferBinding)
+ ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
const int sx0 = sourceRect.left();
const int sx1 = sourceRect.left() + sourceRect.width();
@@ -1696,7 +1728,8 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId);
extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId);
- if (extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
+ const bool supportsMRT = extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets);
+ if (supportsMRT) {
extensions.glReadBuffer(GL_COLOR_ATTACHMENT0 + readColorAttachmentIndex);
if (target) {
GLenum drawBuf = GL_COLOR_ATTACHMENT0 + drawColorAttachmentIndex;
@@ -1708,10 +1741,44 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
tx0, ty0, tx1, ty1,
buffers, filter);
- if (extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets))
+ if (supportsMRT)
extensions.glReadBuffer(GL_COLOR_ATTACHMENT0);
- ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW
+ switch (restorePolicy) {
+ case RestoreFrameBufferBinding:
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW
+ break;
+
+ case RestoreFramebufferBindingToDefault:
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); // sets both READ and DRAW
+ break;
+
+ case DontRestoreFramebufferBinding:
+ break;
+ }
+}
+
+/*!
+ \overload
+
+ Convenience overload to blit between two framebuffer objects and
+ to restore the previous framebuffer binding. Equivalent to calling
+ blitFramebuffer(target, targetRect, source, sourceRect, buffers, filter,
+ readColorAttachmentIndex, drawColorAttachmentIndex,
+ RestoreFrameBufferBinding).
+*/
+void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
+ QOpenGLFramebufferObject *source, const QRect &sourceRect,
+ GLbitfield buffers,
+ GLenum filter,
+ int readColorAttachmentIndex,
+ int drawColorAttachmentIndex)
+{
+ blitFramebuffer(target, targetRect, source, sourceRect,
+ buffers, filter,
+ readColorAttachmentIndex,
+ drawColorAttachmentIndex,
+ RestoreFrameBufferBinding);
}
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglframebufferobject.h b/src/gui/opengl/qopenglframebufferobject.h
index 25d171e289..b22726cafb 100644
--- a/src/gui/opengl/qopenglframebufferobject.h
+++ b/src/gui/opengl/qopenglframebufferobject.h
@@ -114,6 +114,20 @@ public:
static bool hasOpenGLFramebufferObjects();
static bool hasOpenGLFramebufferBlit();
+
+ enum FramebufferRestorePolicy {
+ DontRestoreFramebufferBinding,
+ RestoreFramebufferBindingToDefault,
+ RestoreFrameBufferBinding
+ };
+
+ static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
+ QOpenGLFramebufferObject *source, const QRect &sourceRect,
+ GLbitfield buffers,
+ GLenum filter,
+ int readColorAttachmentIndex,
+ int drawColorAttachmentIndex,
+ FramebufferRestorePolicy restorePolicy);
static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
QOpenGLFramebufferObject *source, const QRect &sourceRect,
GLbitfield buffers,
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 2780de1316..ac6b2df595 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -259,12 +259,21 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *ciph
return ciph;
}
+// static
+inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx) {
+ QSslErrorEntry result = {
+ q_X509_STORE_CTX_get_error(ctx),
+ q_X509_STORE_CTX_get_error_depth(ctx)
+ };
+ return result;
+}
+
// ### This list is shared between all threads, and protected by a
// mutex. Investigate using thread local storage instead.
struct QSslErrorList
{
QMutex mutex;
- QList<QPair<int, int> > errors;
+ QVector<QSslErrorEntry> errors;
};
Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList)
@@ -272,7 +281,7 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx)
{
if (!ok) {
// Store the error and at which depth the error was detected.
- _q_sslErrorList()->errors << qMakePair<int, int>(q_X509_STORE_CTX_get_error(ctx), q_X509_STORE_CTX_get_error_depth(ctx));
+ _q_sslErrorList()->errors << QSslErrorEntry::fromStoreContext(ctx);
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcSsl) << "verification error: dumping bad certificate";
qCDebug(lcSsl) << QSslCertificatePrivate::QSslCertificate_from_X509(q_X509_STORE_CTX_get_current_cert(ctx)).toPem();
@@ -1040,23 +1049,22 @@ bool QSslSocketBackendPrivate::startHandshake()
// Check if the connection has been established. Get all errors from the
// verification stage.
- _q_sslErrorList()->mutex.lock();
+ QMutexLocker locker(&_q_sslErrorList()->mutex);
_q_sslErrorList()->errors.clear();
int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl);
- const QList<QPair<int, int> > &lastErrors = _q_sslErrorList()->errors;
+ const auto &lastErrors = _q_sslErrorList()->errors;
if (!lastErrors.isEmpty())
storePeerCertificates();
- for (int i = 0; i < lastErrors.size(); ++i) {
- const QPair<int, int> &currentError = lastErrors.at(i);
- emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.first,
- configuration.peerCertificateChain.value(currentError.second)));
+ for (const auto &currentError : lastErrors) {
+ emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.code,
+ configuration.peerCertificateChain.value(currentError.depth)));
if (q->state() != QAbstractSocket::ConnectedState)
break;
}
errorList << lastErrors;
- _q_sslErrorList()->mutex.unlock();
+ locker.unlock();
// Connection aborted during handshake phase.
if (q->state() != QAbstractSocket::ConnectedState)
@@ -1133,14 +1141,9 @@ bool QSslSocketBackendPrivate::startHandshake()
}
// Translate errors from the error list into QSslErrors.
- const int numErrors = errorList.size();
- errors.reserve(errors.size() + numErrors);
- for (int i = 0; i < numErrors; ++i) {
- const QPair<int, int> &errorAndDepth = errorList.at(i);
- int err = errorAndDepth.first;
- int depth = errorAndDepth.second;
- errors << _q_OpenSSL_to_QSslError(err, configuration.peerCertificateChain.value(depth));
- }
+ errors.reserve(errors.size() + errorList.size());
+ for (const auto &error : qAsConst(errorList))
+ errors << _q_OpenSSL_to_QSslError(error.code, configuration.peerCertificateChain.value(error.depth));
if (!errors.isEmpty()) {
sslErrors = errors;
@@ -1692,7 +1695,7 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &
#endif
// Now process the errors
- const QList<QPair<int, int> > errorList = _q_sslErrorList()->errors;
+ const auto errorList = std::move(_q_sslErrorList()->errors);
_q_sslErrorList()->errors.clear();
sslErrorListMutexLocker.unlock();
@@ -1711,14 +1714,9 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &
}
// Translate errors from the error list into QSslErrors.
- const int numErrors = errorList.size();
- errors.reserve(errors.size() + numErrors);
- for (int i = 0; i < numErrors; ++i) {
- const QPair<int, int> &errorAndDepth = errorList.at(i);
- int err = errorAndDepth.first;
- int depth = errorAndDepth.second;
- errors << _q_OpenSSL_to_QSslError(err, certificateChain.value(depth));
- }
+ errors.reserve(errors.size() + errorList.size());
+ for (const auto &error : qAsConst(errorList))
+ errors << _q_OpenSSL_to_QSslError(error.code, certificateChain.value(error.depth));
q_X509_STORE_free(certStore);
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index 890576e378..dc60adda39 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -103,6 +103,14 @@ typedef _STACK STACK;
QT_BEGIN_NAMESPACE
+struct QSslErrorEntry {
+ int code;
+ int depth;
+
+ static QSslErrorEntry fromStoreContext(X509_STORE_CTX *ctx);
+};
+Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
+
class QSslSocketBackendPrivate : public QSslSocketPrivate
{
Q_DECLARE_PUBLIC(QSslSocket)
@@ -117,7 +125,7 @@ public:
BIO *readBio;
BIO *writeBio;
SSL_SESSION *session;
- QList<QPair<int, int> > errorList;
+ QVector<QSslErrorEntry> errorList;
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
static int s_indexForSSLExtraData; // index used in SSL_get_ex_data to get the matching QSslSocketBackendPrivate
#endif
diff --git a/src/plugins/bearer/connman/qconnmanservice_linux_p.h b/src/plugins/bearer/connman/qconnmanservice_linux_p.h
index 9a2bf4eb34..e773db9b20 100644
--- a/src/plugins/bearer/connman/qconnmanservice_linux_p.h
+++ b/src/plugins/bearer/connman/qconnmanservice_linux_p.h
@@ -82,8 +82,9 @@ struct ConnmanMap {
QDBusObjectPath objectPath;
QVariantMap propertyMap;
};
-
-typedef QList< ConnmanMap > ConnmanMapList;
+Q_DECLARE_TYPEINFO(ConnmanMap, Q_MOVABLE_TYPE); // QDBusObjectPath is movable, but cannot be
+ // marked as such until Qt 6
+typedef QVector<ConnmanMap> ConnmanMapList;
QT_END_NAMESPACE
diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h
index 43b9570c99..35614a20f2 100644
--- a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h
+++ b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h
@@ -83,7 +83,12 @@ struct ObjectPathProperties
QDBusObjectPath path;
QVariantMap properties;
};
-typedef QList<ObjectPathProperties> PathPropertiesList;
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(ObjectPathProperties, Q_MOVABLE_TYPE); // QDBusObjectPath is movable, but cannot be
+ // marked as such until Qt 6
+QT_END_NAMESPACE
+
+typedef QVector<ObjectPathProperties> PathPropertiesList;
Q_DECLARE_METATYPE(ObjectPathProperties)
Q_DECLARE_METATYPE (PathPropertiesList)
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 1eae295724..6340d47c18 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -78,6 +78,7 @@ static AAssetManager *m_assetManager = nullptr;
static jobject m_resourcesObj = nullptr;
static jobject m_activityObject = nullptr;
static jmethodID m_createSurfaceMethodID = nullptr;
+static jobject m_serviceObject = nullptr;
static jmethodID m_setSurfaceGeometryMethodID = nullptr;
static jmethodID m_destroySurfaceMethodID = nullptr;
@@ -193,6 +194,11 @@ namespace QtAndroid
return m_activityObject;
}
+ jobject service()
+ {
+ return m_serviceObject;
+ }
+
void showStatusBar()
{
if (m_statusBarShowing)
@@ -534,7 +540,6 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para
return pthread_create(&m_qtAppThread, nullptr, startMainMethod, nullptr) == 0;
}
-
static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/)
{
Q_UNUSED(env);
@@ -553,6 +558,8 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
env->DeleteGlobalRef(m_resourcesObj);
if (m_activityObject)
env->DeleteGlobalRef(m_activityObject);
+ if (m_serviceObject)
+ env->DeleteGlobalRef(m_serviceObject);
if (m_bitmapClass)
env->DeleteGlobalRef(m_bitmapClass);
if (m_ARGB_8888_BitmapConfigValue)
@@ -785,20 +792,26 @@ static int registerNatives(JNIEnv *env)
jmethodID methodID;
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
+ jobject serviceObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
clazz = env->GetObjectClass(m_classLoaderObject);
GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ if (serviceObject)
+ m_serviceObject = env->NewGlobalRef(serviceObject);
- if (activityObject) {
+ if (activityObject)
m_activityObject = env->NewGlobalRef(activityObject);
+ jobject object = activityObject ? activityObject : serviceObject;
+ if (object) {
FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
- m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(activityObject, methodID));
+ m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(object, methodID));
GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
- m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(activityObject, methodID));
+ m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID));
FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
@@ -819,8 +832,6 @@ static int registerNatives(JNIEnv *env)
"(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
}
-
-
return JNI_TRUE;
}
diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h
index e3c18b2e7a..218e52ccc1 100644
--- a/src/plugins/platforms/android/androidjnimain.h
+++ b/src/plugins/platforms/android/androidjnimain.h
@@ -83,6 +83,7 @@ namespace QtAndroid
AAssetManager *assetManager();
jclass applicationClass();
jobject activity();
+ jobject service();
void setApplicationActive();
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 1f8ee79396..80d7e31aa3 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -66,7 +66,6 @@
#include "qandroidplatformtheme.h"
#include "qandroidsystemlocale.h"
-
QT_BEGIN_NAMESPACE
int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320;
@@ -87,6 +86,8 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA
return QtAndroid::javaVM();
if (resource == "QtActivity")
return QtAndroid::activity();
+ if (resource == "QtService")
+ return QtAndroid::service();
if (resource == "AndroidStyleData") {
if (m_androidStyle) {
if (m_androidStyle->m_styleData.isEmpty())
@@ -122,7 +123,6 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
#endif
{
Q_UNUSED(paramList);
-
m_androidPlatformNativeInterface = new QAndroidPlatformNativeInterface();
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -159,6 +159,9 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
#endif // QT_NO_ACCESSIBILITY
QJNIObjectPrivate javaActivity(QtAndroid::activity());
+ if (!javaActivity.isValid())
+ javaActivity = QtAndroid::service();
+
if (javaActivity.isValid()) {
QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
@@ -205,13 +208,13 @@ static bool needsBasicRenderloopWorkaround()
bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
{
switch (cap) {
- case ThreadedPixmaps: return true;
case ApplicationState: return true;
- case NativeWidgets: return true;
- case OpenGL: return true;
- case ForeignWindows: return true;
- case ThreadedOpenGL: return !needsBasicRenderloopWorkaround();
- case RasterGLSurface: return true;
+ case ThreadedPixmaps: return true;
+ case NativeWidgets: return QtAndroid::activity();
+ case OpenGL: return QtAndroid::activity();
+ case ForeignWindows: return QtAndroid::activity();
+ case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroid::activity();
+ case RasterGLSurface: return QtAndroid::activity();
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -219,11 +222,15 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const
{
+ if (!QtAndroid::activity())
+ return nullptr;
return new QAndroidPlatformBackingStore(window);
}
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
+ if (!QtAndroid::activity())
+ return nullptr;
QSurfaceFormat format(context->format());
format.setAlphaBufferSize(8);
format.setRedBufferSize(8);
@@ -234,6 +241,8 @@ QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext
QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
+ if (!QtAndroid::activity())
+ return nullptr;
QSurfaceFormat format(surface->requestedFormat());
format.setAlphaBufferSize(8);
format.setRedBufferSize(8);
@@ -245,6 +254,8 @@ QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenS
QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
{
+ if (!QtAndroid::activity())
+ return nullptr;
if (window->type() == Qt::ForeignWindow)
return new QAndroidPlatformForeignWindow(window);
else
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index dd29c29bab..aa4fa94f0a 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -294,6 +294,8 @@ int QAndroidPlatformScreen::rasterSurfaces()
void QAndroidPlatformScreen::doRedraw()
{
PROFILE_SCOPE;
+ if (!QtAndroid::activity())
+ return;
if (m_dirtyRect.isEmpty())
return;
diff --git a/src/plugins/platforms/android/qandroidsystemlocale.cpp b/src/plugins/platforms/android/qandroidsystemlocale.cpp
index 1528d90d06..7fe36aa9bc 100644
--- a/src/plugins/platforms/android/qandroidsystemlocale.cpp
+++ b/src/plugins/platforms/android/qandroidsystemlocale.cpp
@@ -56,6 +56,8 @@ void QAndroidSystemLocale::getLocaleFromJava() const
QJNIObjectPrivate javaLocaleObject;
QJNIObjectPrivate javaActivity(QtAndroid::activity());
+ if (!javaActivity.isValid())
+ javaActivity = QtAndroid::service();
if (javaActivity.isValid()) {
QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 22a2922235..464fcc886f 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -376,12 +376,13 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bo
Q_UNUSED(level);
#else
if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) {
+ const BYTE alpha = BYTE(qRound(255.0 * level));
if (hasAlpha && !openGL && (flags & Qt::FramelessWindowHint)) {
// Non-GL windows with alpha: Use blend function to update.
- BLENDFUNCTION blend = {AC_SRC_OVER, 0, (BYTE)(255.0 * level), AC_SRC_ALPHA};
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
QWindowsContext::user32dll.updateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
} else {
- QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, (int)(level * 255), LWA_ALPHA);
+ QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
}
} else if (IsWindowVisible(hwnd)) { // Repaint when switching from layered.
InvalidateRect(hwnd, NULL, TRUE);
@@ -505,7 +506,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
QVariant prop = w->property("_q_embedded_native_parent_handle");
if (prop.isValid()) {
embedded = true;
- parentHandle = (HWND)prop.value<WId>();
+ parentHandle = reinterpret_cast<HWND>(prop.value<WId>());
}
if (creationFlags & ForceChild) {
@@ -680,10 +681,10 @@ void WindowCreationData::applyWindowFlags(HWND hwnd) const
if (newExStyle != oldExStyle)
SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle);
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << hwnd << *this
- << "\n Style from " << debugWinStyle(oldStyle) << "\n to "
- << debugWinStyle(newStyle) << "\n ExStyle from "
- << debugWinExStyle(oldExStyle) << " to "
- << debugWinExStyle(newExStyle);
+ << "\n Style from " << debugWinStyle(DWORD(oldStyle)) << "\n to "
+ << debugWinStyle(DWORD(newStyle)) << "\n ExStyle from "
+ << debugWinExStyle(DWORD(oldExStyle)) << " to "
+ << debugWinExStyle(DWORD(newExStyle));
}
void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChange, qreal opacityLevel) const
@@ -802,8 +803,8 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co
#ifndef Q_OS_WINCE
void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
{
- return applyToMinMaxInfo(GetWindowLong(hwnd, GWL_STYLE),
- GetWindowLong(hwnd, GWL_EXSTYLE), mmi);
+ return applyToMinMaxInfo(DWORD(GetWindowLong(hwnd, GWL_STYLE)),
+ DWORD(GetWindowLong(hwnd, GWL_EXSTYLE)), mmi);
}
void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
@@ -1363,7 +1364,7 @@ void QWindowsWindow::updateTransientParent() const
if (!tw->testFlag(WithinDestroy)) // Prevent destruction by parent window (QTBUG-35499, QTBUG-36666)
newTransientParent = tw->handle();
if (newTransientParent != oldTransientParent)
- SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent);
+ SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, LONG_PTR(newTransientParent));
#endif // !Q_OS_WINCE
}
@@ -2015,7 +2016,7 @@ QMargins QWindowsWindow::frameMargins() const
void QWindowsWindow::setOpacity(qreal level)
{
qCDebug(lcQpaWindows) << __FUNCTION__ << level;
- if (m_opacity != level) {
+ if (!qFuzzyCompare(m_opacity, level)) {
m_opacity = level;
if (m_data.hwnd)
setWindowOpacity(m_data.hwnd, m_data.flags,
@@ -2317,7 +2318,7 @@ void QWindowsWindow::setAlertState(bool enabled)
void QWindowsWindow::alertWindow(int durationMs)
{
- DWORD timeOutMs = GetCaretBlinkTime();
+ UINT timeOutMs = GetCaretBlinkTime();
if (!timeOutMs || timeOutMs == INFINITE)
timeOutMs = 250;
@@ -2326,7 +2327,7 @@ void QWindowsWindow::alertWindow(int durationMs)
info.hwnd = m_data.hwnd;
info.dwFlags = FLASHW_TRAY;
info.dwTimeout = timeOutMs;
- info.uCount = durationMs == 0 ? 10 : durationMs / timeOutMs;
+ info.uCount = durationMs == 0 ? 10 : UINT(durationMs) / timeOutMs;
FlashWindowEx(&info);
}
@@ -2379,11 +2380,11 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon)
m_iconBig = createHIcon(icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
if (m_iconBig) {
- SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)m_iconSmall);
- SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)m_iconBig);
+ SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, LPARAM(m_iconSmall));
+ SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, LPARAM(m_iconBig));
} else {
- SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)m_iconSmall);
- SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)m_iconSmall);
+ SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, LPARAM(m_iconSmall));
+ SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, LPARAM(m_iconSmall));
}
}
}
@@ -2464,7 +2465,7 @@ void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTou
// such as HCBT_CREATEWND
if (ret || touchFlags != 0)
return;
- if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, (ULONG)touchTypes))
+ if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, ULONG(touchTypes)))
setFlag(TouchRegistered);
else
qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
diff --git a/src/printsupport/dialogs/qprintpreviewdialog.cpp b/src/printsupport/dialogs/qprintpreviewdialog.cpp
index 97acbb79a1..435f8869c4 100644
--- a/src/printsupport/dialogs/qprintpreviewdialog.cpp
+++ b/src/printsupport/dialogs/qprintpreviewdialog.cpp
@@ -250,8 +250,8 @@ void QPrintPreviewDialogPrivate::init(QPrinter *_printer)
zoomEditor->setValidator(new ZoomFactorValidator(1, 1000, 1, zoomEditor));
zoomFactor->setLineEdit(zoomEditor);
static const short factorsX2[] = { 25, 50, 100, 200, 250, 300, 400, 800, 1600 };
- for (int i = 0; i < int(sizeof(factorsX2) / sizeof(factorsX2[0])); ++i)
- zoomFactor->addItem(QPrintPreviewDialog::tr("%1%").arg(factorsX2[i] / 2.0));
+ for (auto factorX2 : factorsX2)
+ zoomFactor->addItem(QPrintPreviewDialog::tr("%1%").arg(factorX2 / 2.0));
QObject::connect(zoomFactor->lineEdit(), SIGNAL(editingFinished()),
q, SLOT(_q_zoomFactorChanged()));
QObject::connect(zoomFactor, SIGNAL(currentIndexChanged(int)),
diff --git a/src/printsupport/kernel/qpaintengine_alpha.cpp b/src/printsupport/kernel/qpaintengine_alpha.cpp
index 4922d210f2..939322cc07 100644
--- a/src/printsupport/kernel/qpaintengine_alpha.cpp
+++ b/src/printsupport/kernel/qpaintengine_alpha.cpp
@@ -336,8 +336,8 @@ void QAlphaPaintEngine::flushAndInit(bool init)
d->resetState(painter());
// fill in the alpha images
- for (int i=0; i<rects.size(); ++i)
- d->drawAlphaImage(rects.at(i));
+ for (const auto &rect : qAsConst(rects))
+ d->drawAlphaImage(rect);
d->m_alphargn = QRegion();
diff --git a/src/printsupport/kernel/qprintdevice.cpp b/src/printsupport/kernel/qprintdevice.cpp
index 29dd0d6529..26799a6f13 100644
--- a/src/printsupport/kernel/qprintdevice.cpp
+++ b/src/printsupport/kernel/qprintdevice.cpp
@@ -283,10 +283,10 @@ void QPrintDevice::format(QDebug debug) const
<< ", defaultColorMode="<< defaultColorMode();
# ifndef QT_NO_MIMETYPE
const QList<QMimeType> mimeTypes = supportedMimeTypes();
- if (const int mimeTypeCount = mimeTypes.size()) {
+ if (!mimeTypes.isEmpty()) {
debug << ", supportedMimeTypes=(";
- for (int i = 0; i < mimeTypeCount; ++i)
- debug << " \"" << mimeTypes.at(i).name() << '"';
+ for (const auto &mimeType : mimeTypes)
+ debug << " \"" << mimeType.name() << '"';
debug << ')';
}
# endif // !QT_NO_MIMETYPE
diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp
index cc4c8244ae..cbab151ea0 100644
--- a/src/printsupport/kernel/qprinter.cpp
+++ b/src/printsupport/kernel/qprinter.cpp
@@ -1946,13 +1946,12 @@ int QPrinter::winPageSize() const
QList<int> QPrinter::supportedResolutions() const
{
Q_D(const QPrinter);
- QList<QVariant> varlist
+ const QList<QVariant> varlist
= d->printEngine->property(QPrintEngine::PPK_SupportedResolutions).toList();
QList<int> intlist;
- const int numSupportedResolutions = varlist.size();
- intlist.reserve(numSupportedResolutions);
- for (int i = 0; i < numSupportedResolutions; ++i)
- intlist << varlist.at(i).toInt();
+ intlist.reserve(varlist.size());
+ for (auto var : varlist)
+ intlist << var.toInt();
return intlist;
}
@@ -2015,10 +2014,11 @@ QList<QPrinter::PaperSource> QPrinter::supportedPaperSources() const
Q_D(const QPrinter);
QVariant v = d->printEngine->property(QPrintEngine::PPK_PaperSources);
- QList<QVariant> variant_list = v.toList();
+ const QList<QVariant> variant_list = v.toList();
QList<QPrinter::PaperSource> int_list;
- for (int i=0; i<variant_list.size(); ++i)
- int_list << (QPrinter::PaperSource) variant_list.at(i).toInt();
+ int_list.reserve(variant_list.size());
+ for (const auto &variant : variant_list)
+ int_list << QPrinter::PaperSource(variant.toInt());
return int_list;
}
diff --git a/src/printsupport/widgets/qprintpreviewwidget.cpp b/src/printsupport/widgets/qprintpreviewwidget.cpp
index 2de487e937..fd1cf68587 100644
--- a/src/printsupport/widgets/qprintpreviewwidget.cpp
+++ b/src/printsupport/widgets/qprintpreviewwidget.cpp
@@ -295,9 +295,9 @@ int QPrintPreviewWidgetPrivate::calcCurrentPage()
int maxArea = 0;
int newPage = curPage;
QRect viewRect = graphicsView->viewport()->rect();
- QList<QGraphicsItem*> items = graphicsView->items(viewRect);
- for (int i=0; i<items.size(); ++i) {
- PageItem* pg = static_cast<PageItem*>(items.at(i));
+ const QList<QGraphicsItem*> items = graphicsView->items(viewRect);
+ for (auto *item : items) {
+ PageItem* pg = static_cast<PageItem*>(item);
QRect overlap = graphicsView->mapFromScene(pg->sceneBoundingRect()).boundingRect() & viewRect;
int area = overlap.width() * overlap.height();
if (area > maxArea) {
@@ -335,17 +335,17 @@ void QPrintPreviewWidgetPrivate::init()
void QPrintPreviewWidgetPrivate::populateScene()
{
// remove old pages
- for (int i = 0; i < pages.size(); i++)
- scene->removeItem(pages.at(i));
+ for (auto *page : qAsConst(pages))
+ scene->removeItem(page);
qDeleteAll(pages);
pages.clear();
- int numPages = pictures.count();
QSize paperSize = printer->pageLayout().fullRectPixels(printer->resolution()).size();
QRect pageRect = printer->pageLayout().paintRectPixels(printer->resolution());
- for (int i = 0; i < numPages; i++) {
- PageItem* item = new PageItem(i+1, pictures.at(i), paperSize, pageRect);
+ int page = 1;
+ for (auto *picture : qAsConst(pictures)) {
+ PageItem* item = new PageItem(page++, picture, paperSize, pageRect);
scene->addItem(item);
pages.append(item);
}
diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp
index 14a04d269f..47d6db7ea4 100644
--- a/src/sql/drivers/oci/qsql_oci.cpp
+++ b/src/sql/drivers/oci/qsql_oci.cpp
@@ -2386,17 +2386,46 @@ bool QOCIDriver::rollbackTransaction()
return true;
}
+enum Expression {
+ OrExpression,
+ AndExpression
+};
+
+static QString make_where_clause(const QString &user, Expression e)
+{
+ static const char sysUsers[][8] = {
+ "MDSYS",
+ "LBACSYS",
+ "SYS",
+ "SYSTEM",
+ "WKSYS",
+ "CTXSYS",
+ "WMSYS",
+ };
+ static const char joinC[][4] = { "or" , "and" };
+ static Q_CONSTEXPR QLatin1Char bang[] = { QLatin1Char(' '), QLatin1Char('!') };
+
+ const QLatin1String join(joinC[e], -1); // -1: force strlen call
+
+ QString result;
+ result.reserve(sizeof sysUsers / sizeof *sysUsers *
+ // max-sizeof(owner != <sysuser> and )
+ (9 + sizeof *sysUsers + 5));
+ for (const auto &sysUser : sysUsers) {
+ const QLatin1String l1(sysUser, -1); // -1: force strlen call
+ if (l1 != user)
+ result += QLatin1String("owner ") + bang[e] + QLatin1String("= '") + l1 + QLatin1Char(' ') + join + QLatin1Char(' ');
+ }
+
+ result.chop(join.size() + 2); // remove final " <join> "
+
+ return result;
+}
+
QStringList QOCIDriver::tables(QSql::TableType type) const
{
Q_D(const QOCIDriver);
QStringList tl;
- QStringList sysUsers = QStringList() << QLatin1String("MDSYS")
- << QLatin1String("LBACSYS")
- << QLatin1String("SYS")
- << QLatin1String("SYSTEM")
- << QLatin1String("WKSYS")
- << QLatin1String("CTXSYS")
- << QLatin1String("WMSYS");
QString user = d->user;
if ( isIdentifierEscaped(user, QSqlDriver::TableName))
@@ -2404,21 +2433,15 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
else
user = user.toUpper();
- if(sysUsers.contains(user))
- sysUsers.removeAll(user);;
-
if (!isOpen())
return tl;
QSqlQuery t(createResult());
t.setForwardOnly(true);
if (type & QSql::Tables) {
- QString query = QLatin1String("select owner, table_name from all_tables where ");
- QStringList whereList;
- foreach(const QString &sysUserName, sysUsers)
- whereList << QLatin1String("owner != '") + sysUserName + QLatin1String("' ");
- t.exec(query + whereList.join(QLatin1String(" and ")));
-
+ const QLatin1String tableQuery("select owner, table_name from all_tables where ");
+ const QString where = make_where_clause(user, AndExpression);
+ t.exec(tableQuery + where);
while (t.next()) {
if (t.value(0).toString().toUpper() != user.toUpper())
tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
@@ -2427,8 +2450,8 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
}
// list all table synonyms as well
- query = QLatin1String("select owner, synonym_name from all_synonyms where ");
- t.exec(query + whereList.join(QLatin1String(" and ")));
+ const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
+ t.exec(synonymQuery + where);
while (t.next()) {
if (t.value(0).toString() != d->user)
tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
@@ -2437,11 +2460,9 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
}
}
if (type & QSql::Views) {
- QString query = QLatin1String("select owner, view_name from all_views where ");
- QStringList whereList;
- foreach(const QString &sysUserName, sysUsers)
- whereList << QLatin1String("owner != '") + sysUserName + QLatin1String("' ");
- t.exec(query + whereList.join(QLatin1String(" and ")));
+ const QLatin1String query("select owner, view_name from all_views where ");
+ const QString where = make_where_clause(user, AndExpression);
+ t.exec(query + where);
while (t.next()) {
if (t.value(0).toString().toUpper() != d->user.toUpper())
tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
@@ -2454,12 +2475,9 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
while (t.next()) {
tl.append(t.value(0).toString());
}
- QString query = QLatin1String("select owner, table_name from all_tables where ");
- QStringList whereList;
- foreach(const QString &sysUserName, sysUsers)
- whereList << QLatin1String("owner = '") + sysUserName + QLatin1String("' ");
- t.exec(query + whereList.join(QLatin1String(" or ")));
-
+ const QLatin1String tableQuery("select owner, table_name from all_tables where ");
+ const QString where = make_where_clause(user, OrExpression);
+ t.exec(tableQuery + where);
while (t.next()) {
if (t.value(0).toString().toUpper() != user.toUpper())
tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
@@ -2468,8 +2486,8 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
}
// list all table synonyms as well
- query = QLatin1String("select owner, synonym_name from all_synonyms where ");
- t.exec(query + whereList.join(QLatin1String(" or ")));
+ const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
+ t.exec(synonymQuery + where);
while (t.next()) {
if (t.value(0).toString() != d->user)
tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp
index c1071c9222..2a45b73d14 100644
--- a/src/sql/drivers/sqlite/qsql_sqlite.cpp
+++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp
@@ -613,13 +613,17 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
bool openReadOnlyOption = false;
bool openUriOption = false;
- const QStringList opts = QString(conOpts).remove(QLatin1Char(' ')).split(QLatin1Char(';'));
- foreach (const QString &option, opts) {
- if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT="))) {
- bool ok;
- const int nt = option.midRef(21).toInt(&ok);
- if (ok)
- timeOut = nt;
+ const auto opts = conOpts.splitRef(QLatin1Char(';'));
+ for (auto option : opts) {
+ option = option.trimmed();
+ if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT"))) {
+ option = option.mid(20).trimmed();
+ if (option.startsWith(QLatin1Char('='))) {
+ bool ok;
+ const int nt = option.mid(1).trimmed().toInt(&ok);
+ if (ok)
+ timeOut = nt;
+ }
} else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) {
openReadOnlyOption = true;
} else if (option == QLatin1String("QSQLITE_OPEN_URI")) {
@@ -657,9 +661,8 @@ void QSQLiteDriver::close()
{
Q_D(QSQLiteDriver);
if (isOpen()) {
- foreach (QSQLiteResult *result, d->results) {
+ for (QSQLiteResult *result : qAsConst(d->results))
result->d_func()->finalize();
- }
if (sqlite3_close(d->access) != SQLITE_OK)
setLastError(qMakeError(d->access, tr("Error closing database"),
diff --git a/src/sql/kernel/qsqlcachedresult.cpp b/src/sql/kernel/qsqlcachedresult.cpp
index 3bacffed75..c335d7d8fe 100644
--- a/src/sql/kernel/qsqlcachedresult.cpp
+++ b/src/sql/kernel/qsqlcachedresult.cpp
@@ -267,7 +267,6 @@ bool QSqlCachedResult::cacheNext()
return false;
if(isForwardOnly()) {
- d->cache.clear();
d->cache.resize(d->colCount);
}
diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp
index 5e4c024480..f79c1c71cd 100644
--- a/src/sql/kernel/qsqlresult.cpp
+++ b/src/sql/kernel/qsqlresult.cpp
@@ -709,8 +709,8 @@ void QSqlResult::bindValue(const QString& placeholder, const QVariant& val,
d->binds = NamedBinding;
// if the index has already been set when doing emulated named
// bindings - don't reset it
- QList<int> indexes = d->indexes.value(placeholder);
- foreach (int idx, indexes) {
+ const QList<int> indexes = d->indexes.value(placeholder);
+ for (int idx : indexes) {
if (d->values.count() <= idx)
d->values.resize(idx + 1);
d->values[idx] = val;
diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp
index 3612787fca..0bc86494f9 100644
--- a/src/sql/models/qsqltablemodel.cpp
+++ b/src/sql/models/qsqltablemodel.cpp
@@ -736,7 +736,8 @@ bool QSqlTableModel::submitAll()
bool success = true;
- foreach (int row, d->cache.keys()) {
+ const auto cachedKeys = d->cache.keys();
+ for (int row : cachedKeys) {
// be sure cache *still* contains the row since overridden selectRow() could have called select()
QSqlTableModelPrivate::CacheMap::iterator it = d->cache.find(row);
if (it == d->cache.end())
diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro
index 0faa1c7d30..85fb0cd2fe 100644
--- a/src/testlib/testlib.pro
+++ b/src/testlib/testlib.pro
@@ -78,8 +78,8 @@ mac {
LIBS += -framework Security
osx: LIBS += -framework ApplicationServices -framework IOKit
- # XCTest support
- !lessThan(QMAKE_XCODE_VERSION, "6.0") {
+ # XCTest support (disabled for now)
+ false:!lessThan(QMAKE_XCODE_VERSION, "6.0") {
OBJECTIVE_SOURCES += qxctestlogger.mm
HEADERS += qxctestlogger_p.h
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
index 47f2e76faf..9f86bea0ca 100644
--- a/src/widgets/dialogs/qcolordialog.cpp
+++ b/src/widgets/dialogs/qcolordialog.cpp
@@ -1909,10 +1909,11 @@ bool QColorDialogPrivate::canBeNativeDialog() const
Q_Q(const QColorDialog);
if (nativeDialogInUse)
return true;
- if (q->testAttribute(Qt::WA_DontShowOnScreen))
- return false;
- if (q->options() & QColorDialog::DontUseNativeDialog)
+ if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+ || q->testAttribute(Qt::WA_DontShowOnScreen)
+ || (q->options() & QColorDialog::DontUseNativeDialog)) {
return false;
+ }
QLatin1String staticName(QColorDialog::staticMetaObject.className());
QLatin1String dynamicName(q->metaObject()->className());
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index af4fd235d5..07422f8811 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -704,10 +704,11 @@ bool QFileDialogPrivate::canBeNativeDialog() const
Q_Q(const QFileDialog);
if (nativeDialogInUse)
return true;
- if (q->testAttribute(Qt::WA_DontShowOnScreen))
- return false;
- if (q->options() & QFileDialog::DontUseNativeDialog)
+ if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+ || q->testAttribute(Qt::WA_DontShowOnScreen)
+ || (q->options() & QFileDialog::DontUseNativeDialog)) {
return false;
+ }
QLatin1String staticName(QFileDialog::staticMetaObject.className());
QLatin1String dynamicName(q->metaObject()->className());
diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp
index 7dbcf15b73..a0525f6fbd 100644
--- a/src/widgets/dialogs/qfontdialog.cpp
+++ b/src/widgets/dialogs/qfontdialog.cpp
@@ -1043,10 +1043,11 @@ bool QFontDialogPrivate::canBeNativeDialog() const
Q_Q(const QFontDialog);
if (nativeDialogInUse)
return true;
- if (q->testAttribute(Qt::WA_DontShowOnScreen))
- return false;
- if (options->options() & QFontDialog::DontUseNativeDialog)
+ if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+ || q->testAttribute(Qt::WA_DontShowOnScreen)
+ || (options->options() & QFontDialog::DontUseNativeDialog)) {
return false;
+ }
QLatin1String staticName(QFontDialog::staticMetaObject.className());
QLatin1String dynamicName(q->metaObject()->className());
diff --git a/src/widgets/itemviews/qdirmodel.cpp b/src/widgets/itemviews/qdirmodel.cpp
index 37ba5a59f8..dfb1d7619e 100644
--- a/src/widgets/itemviews/qdirmodel.cpp
+++ b/src/widgets/itemviews/qdirmodel.cpp
@@ -136,11 +136,12 @@ public:
QPersistentModelIndexData *data;
QPersistentModelIndex index;
};
- QList<SavedPersistent> savedPersistent;
+ QVector<SavedPersistent> savedPersistent;
QPersistentModelIndex toBeRefreshed;
bool shouldStat; // use the "carefull not to stat directories" mode
};
+Q_DECLARE_TYPEINFO(QDirModelPrivate::SavedPersistent, Q_MOVABLE_TYPE);
void qt_setDirModelShouldNotStat(QDirModelPrivate *modelPrivate)
{
@@ -1237,14 +1238,16 @@ void QDirModelPrivate::savePersistentIndexes()
{
Q_Q(QDirModel);
savedPersistent.clear();
+ savedPersistent.reserve(persistent.indexes.size());
foreach (QPersistentModelIndexData *data, persistent.indexes) {
- SavedPersistent saved;
QModelIndex index = data->index;
- saved.path = q->filePath(index);
- saved.column = index.column();
- saved.data = data;
- saved.index = index;
- savedPersistent.append(saved);
+ SavedPersistent saved = {
+ q->filePath(index),
+ index.column(),
+ data,
+ index,
+ };
+ savedPersistent.push_back(std::move(saved));
}
}
@@ -1253,11 +1256,9 @@ void QDirModelPrivate::restorePersistentIndexes()
Q_Q(QDirModel);
bool allow = allowAppendChild;
allowAppendChild = false;
- for (int i = 0; i < savedPersistent.count(); ++i) {
- QPersistentModelIndexData *data = savedPersistent.at(i).data;
- QString path = savedPersistent.at(i).path;
- int column = savedPersistent.at(i).column;
- QModelIndex idx = q->index(path, column);
+ for (const SavedPersistent &sp : qAsConst(savedPersistent)) {
+ QPersistentModelIndexData *data = sp.data;
+ QModelIndex idx = q->index(sp.path, sp.column);
if (idx != data->index || data->model == 0) {
//data->model may be equal to 0 if the model is getting destroyed
persistent.indexes.remove(data->index);
diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp
index 00e0774012..6fc8cb5e26 100644
--- a/src/widgets/widgets/qdialogbuttonbox.cpp
+++ b/src/widgets/widgets/qdialogbuttonbox.cpp
@@ -288,13 +288,8 @@ void QDialogButtonBoxPrivate::layoutButtons()
}
break;
case QPlatformDialogHelper::AlternateRole:
- {
- if (acceptRoleList.size() < 2)
- break;
- QList<QAbstractButton *> list = acceptRoleList;
- list.removeFirst();
- addButtonsToLayout(list, reverse);
- }
+ if (acceptRoleList.size() > 1)
+ addButtonsToLayout(acceptRoleList.mid(1), reverse);
break;
case QPlatformDialogHelper::DestructiveRole:
{
diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro b/tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro
index eef165d9f7..3c12a83f5a 100644
--- a/tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro
+++ b/tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro
@@ -4,6 +4,10 @@ TARGET = tst_qstandarditemmodel
QT += widgets widgets-private testlib
QT += core-private gui-private
-SOURCES += tst_qstandarditemmodel.cpp
+mtdir = ../../../other/modeltest
+INCLUDEPATH += $${mtdir}
+
+SOURCES += $${mtdir}/modeltest.cpp tst_qstandarditemmodel.cpp
+HEADERS += $${mtdir}/modeltest.h
diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp
index 7e9e5a6e96..dca718a6d8 100644
--- a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp
+++ b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp
@@ -32,6 +32,7 @@
#include <qstandarditemmodel.h>
#include <QTreeView>
#include <private/qtreeview_p.h>
+#include "modeltest.h"
class tst_QStandardItemModel : public QObject
{
@@ -734,6 +735,9 @@ void tst_QStandardItemModel::clear()
QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
QSignalSpy layoutChangedSpy(&model, SIGNAL(layoutChanged()));
QSignalSpy rowsRemovedSpy(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)));
+
+ ModelTest mt(&model);
+
model.clear();
QCOMPARE(modelResetSpy.count(), 1);
diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp
index 871251df2e..d43f700caa 100644
--- a/tools/configure/configureapp.cpp
+++ b/tools/configure/configureapp.cpp
@@ -4539,18 +4539,18 @@ bool Configure::showLicense(QString orgLicenseFile)
return true;
}
- bool showLgpl2 = true;
+ bool showGpl2 = true;
QString licenseFile = orgLicenseFile;
QString theLicense;
if (dictionary["EDITION"] == "OpenSource") {
if (platform() != WINDOWS_RT
&& platform() != WINDOWS_CE
&& (platform() != ANDROID || dictionary["ANDROID_STYLE_ASSETS"] == "no")) {
- theLicense = "GNU Lesser General Public License (LGPL) version 2.1"
- "\nor the GNU Lesser General Public License (LGPL) version 3";
+ theLicense = "GNU Lesser General Public License (LGPL) version 3\n"
+ "or the GNU General Public License (GPL) version 2";
} else {
theLicense = "GNU Lesser General Public License (LGPL) version 3";
- showLgpl2 = false;
+ showGpl2 = false;
}
} else {
// the first line of the license file tells us which license it is
@@ -4568,9 +4568,9 @@ bool Configure::showLicense(QString orgLicenseFile)
<< "the " << theLicense << "." << endl
<< endl;
if (dictionary["EDITION"] == "OpenSource") {
- cout << "Type '3' to view the Lesser GNU General Public License version 3 (LGPLv3)." << endl;
- if (showLgpl2)
- cout << "Type 'L' to view the Lesser GNU General Public License version 2.1 (LGPLv2.1)." << endl;
+ cout << "Type 'L' to view the GNU Lesser General Public License version 3 (LGPLv3)." << endl;
+ if (showGpl2)
+ cout << "Type 'G' to view the GNU General Public License version 2 (GPLv2)." << endl;
} else {
cout << "Type '?' to view the " << theLicense << "." << endl;
}
@@ -4587,10 +4587,10 @@ bool Configure::showLicense(QString orgLicenseFile)
return false;
} else {
if (dictionary["EDITION"] == "OpenSource") {
- if (accept == '3')
- licenseFile = orgLicenseFile + "/LICENSE.LGPLv3";
+ if (accept == 'L')
+ licenseFile = orgLicenseFile + "/LICENSE.LGPL3";
else
- licenseFile = orgLicenseFile + "/LICENSE.LGPLv21";
+ licenseFile = orgLicenseFile + "/LICENSE.GPL2";
}
// Get console line height, to fill the screen properly
int i = 0, screenHeight = 25; // default
@@ -4625,7 +4625,7 @@ void Configure::readLicense()
dictionary["LICENSE FILE"] = sourcePath;
bool openSource = false;
- bool hasOpenSource = QFile::exists(dictionary["LICENSE FILE"] + "/LICENSE.LGPLv3") || QFile::exists(dictionary["LICENSE FILE"] + "/LICENSE.LGPLv21");
+ bool hasOpenSource = QFile::exists(dictionary["LICENSE FILE"] + "/LICENSE.LGPL3") || QFile::exists(dictionary["LICENSE FILE"] + "/LICENSE.GPL2");
if (dictionary["BUILDTYPE"] == "commercial") {
openSource = false;
} else if (dictionary["BUILDTYPE"] == "opensource") {