Introducing the Qt Android port
Based on the Necessitas project by Bogdan Vatra. Contributors to the Qt5 project: BogDan Vatra <bogdan@kde.org> Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com> hjk <hjk121@nokiamail.com> Oswald Buddenhagen <oswald.buddenhagen@digia.com> Paul Olav Tvete <paul.tvete@digia.com> Robin Burchell <robin+qt@viroteck.net> Samuel Rødal <samuel.rodal@digia.com> Yoann Lopes <yoann.lopes@digia.com> The full history of the Qt5 port can be found in refs/old-heads/android, SHA-1 249ca9ca2c7d876b91b31df9434dde47f9065d0d Change-Id: Iff1a7b2dbb707c986f2639e65e39ed8f22430120 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
parent
1b582d64eb
commit
97fcf3bc98
@ -40,6 +40,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <sys/kd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
int main(int, char **)
|
||||
|
@ -36,6 +36,8 @@ if [ -f ./arch.exe ]; then
|
||||
binary=./arch.exe
|
||||
elif [ -f ./arch ]; then
|
||||
binary=./arch
|
||||
elif [ -f ./libarch.so ]; then
|
||||
binary=./libarch.so
|
||||
else
|
||||
[ "$VERBOSE" = "yes" ] && echo "Unable to determine architecture!"
|
||||
exit 2
|
||||
|
@ -67,7 +67,7 @@ test -r Makefile && $MAKE distclean >/dev/null 2>&1
|
||||
# Make sure output from possible previous tests is gone
|
||||
rm -f "$EXE" "${EXE}.exe"
|
||||
|
||||
set -- "$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "CONFIG+=$QMAKE_CONFIG" "CONFIG-=debug_and_release" "LIBS*=$LFLAGS" "LIBS+=$MAC_ARCH_LFLAGS" "INCLUDEPATH*=$INCLUDEPATH" "QMAKE_CXXFLAGS*=$CXXFLAGS" "QMAKE_CXXFLAGS+=$MAC_ARCH_CXXFLAGS" "QT_BUILD_TREE=$OUTDIR" "$SRCDIR/$TEST/$EXE.pro" -o "$OUTDIR/$TEST/Makefile"
|
||||
set -- "$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "CONFIG+=$QMAKE_CONFIG" "CONFIG+=android_app" "CONFIG-=debug_and_release" "LIBS*=$LFLAGS" "LIBS+=$MAC_ARCH_LFLAGS" "INCLUDEPATH*=$INCLUDEPATH" "QMAKE_CXXFLAGS*=$CXXFLAGS" "QMAKE_CXXFLAGS+=$MAC_ARCH_CXXFLAGS" "QT_BUILD_TREE=$OUTDIR" "$SRCDIR/$TEST/$EXE.pro" -o "$OUTDIR/$TEST/Makefile"
|
||||
if [ "$VERBOSE" = "yes" ]; then
|
||||
OUTDIR=$OUTDIR "$@"
|
||||
$MAKE
|
||||
|
172
configure
vendored
172
configure
vendored
@ -875,6 +875,7 @@ RPATH_FLAGS=
|
||||
W_FLAGS=
|
||||
QCONFIG_FLAGS=
|
||||
XPLATFORM= # This seems to be the QMAKESPEC, like "linux-g++"
|
||||
XPLATFORM_ANDROID=no
|
||||
XPLATFORM_MINGW=no # Whether target platform is MinGW (win32-g++*)
|
||||
XPLATFORM_MAEMO=no
|
||||
XPLATFORM_QNX=no
|
||||
@ -955,6 +956,15 @@ CFG_SQL_oci=no
|
||||
CFG_SQL_db2=no
|
||||
|
||||
CFG_SQL_AVAILABLE=
|
||||
|
||||
# Android vars
|
||||
CFG_DEFAULT_ANDROID_NDK_ROOT=$ANDROID_NDK_ROOT
|
||||
CFG_DEFAULT_ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT
|
||||
CFG_DEFAULT_ANDROID_PLATFORM=android-9
|
||||
CFG_DEFAULT_ANDROID_TARGET_ARCH=armeabi-v7a
|
||||
CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION=4.7
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=$ANDROID_NDK_HOST
|
||||
|
||||
if [ -d "$relpath/src/plugins/sqldrivers" ]; then
|
||||
for a in "$relpath/src/plugins/sqldrivers/"*; do
|
||||
if [ -d "$a" ]; then
|
||||
@ -1016,7 +1026,7 @@ while [ "$#" -gt 0 ]; do
|
||||
VAL=no
|
||||
;;
|
||||
#Qt style options that pass an argument
|
||||
-prefix|-docdir|-headerdir|-plugindir|-importdir|-qmldir|-archdatadir|-datadir|-libdir|-bindir|-libexecdir|-translationdir|-sysconfdir|-examplesdir|-testsdir|-depths|-make|-nomake|-platform|-xplatform|-device|-device-option|-sdk|-arch|-host-arch|-mysql_config|-sysroot|-hostdatadir|-hostbindir|-qpa|-qconfig)
|
||||
-prefix|-docdir|-headerdir|-plugindir|-importdir|-qmldir|-archdatadir|-datadir|-libdir|-bindir|-libexecdir|-translationdir|-sysconfdir|-examplesdir|-testsdir|-depths|-make|-nomake|-platform|-xplatform|-device|-device-option|-sdk|-arch|-host-arch|-mysql_config|-sysroot|-hostdatadir|-hostbindir|-qpa|-qconfig|-android-sdk|-android-ndk|-android-ndk-platform|-android-ndk-host|-android-arch|-android-toolchain-version)
|
||||
VAR=`echo $1 | sed "s,^-\(.*\),\1,"`
|
||||
shift
|
||||
VAL="$1"
|
||||
@ -2148,6 +2158,24 @@ while [ "$#" -gt 0 ]; do
|
||||
UNKNOWN_OPT=yes
|
||||
fi
|
||||
;;
|
||||
android-sdk)
|
||||
CFG_DEFAULT_ANDROID_SDK_ROOT="$VAL"
|
||||
;;
|
||||
android-ndk)
|
||||
CFG_DEFAULT_ANDROID_NDK_ROOT="$VAL"
|
||||
;;
|
||||
android-ndk-platform)
|
||||
CFG_DEFAULT_ANDROID_PLATFORM="$VAL"
|
||||
;;
|
||||
android-ndk-host)
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST="$VAL"
|
||||
;;
|
||||
android-arch)
|
||||
CFG_DEFAULT_ANDROID_TARGET_ARCH="$VAL"
|
||||
;;
|
||||
android-toolchain-version)
|
||||
CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION="$VAL"
|
||||
;;
|
||||
*)
|
||||
UNKNOWN_OPT=yes
|
||||
;;
|
||||
@ -2520,9 +2548,89 @@ fi
|
||||
[ -z "$XPLATFORM" ] && XPLATFORM="$PLATFORM"
|
||||
|
||||
case `basename "$XPLATFORM"` in win32-g++*) XPLATFORM_MINGW=yes;; esac
|
||||
case "$XPLATFORM" in *-maemo*) XPLATFORM_MAEMO=yes;; esac
|
||||
case "$XPLATFORM" in *qnx-*|*blackberry-*) XPLATFORM_QNX=yes;; esac
|
||||
case "$XPLATFORM" in *ios*) XPLATFORM_IOS=yes;; esac
|
||||
case "$XPLATFORM" in
|
||||
*-maemo*)
|
||||
XPLATFORM_MAEMO=yes
|
||||
;;
|
||||
*qnx-*|*blackberry-*)
|
||||
XPLATFORM_QNX=yes
|
||||
;;
|
||||
*ios*)
|
||||
XPLATFORM_IOS=yes
|
||||
;;
|
||||
# XPLATFORM_ANDROID should not be set for unsupported/android-g++
|
||||
*unsupported*)
|
||||
;;
|
||||
*android-g++*)
|
||||
XPLATFORM_ANDROID=yes
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$XPLATFORM_ANDROID" = "yes" ]; then
|
||||
if [ -z "$CFG_DEFAULT_ANDROID_NDK_HOST" ]; then
|
||||
case $PLATFORM in
|
||||
linux-*-64)
|
||||
if [ -d "$CFG_DEFAULT_ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION/prebuilt/linux-x86_64" ]; then
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=linux-x86_64
|
||||
else
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=linux-x86
|
||||
fi
|
||||
;;
|
||||
linux-*)
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=linux-x86
|
||||
;;
|
||||
macx-*)
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=darwin-x86
|
||||
if [ ! -z "$NATIVE_64_ARCH" ] && [ -d "$CFG_DEFAULT_ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION/prebuilt/darwin-x86_64" ]; then
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=darwin-x86_64
|
||||
fi
|
||||
;;
|
||||
win32-*)
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=windows
|
||||
if [ ! -z "$NATIVE_64_ARCH" ] && [ -d "$CFG_DEFAULT_ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION/prebuilt/windows-x86_64" ]; then
|
||||
CFG_DEFAULT_ANDROID_NDK_HOST=windows-x86_64
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$OPT_HELP" != "yes" ]; then
|
||||
if [ -z "$CFG_DEFAULT_ANDROID_NDK_ROOT" ]; then
|
||||
echo
|
||||
echo "Can not find Android NDK. Please use -android-ndk option to specify one"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$CFG_DEFAULT_ANDROID_SDK_ROOT" ]; then
|
||||
echo
|
||||
echo "Can not find Android SDK. Please use -android-sdk option to specify one"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION" ] || [ ! -d "$CFG_DEFAULT_ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION/prebuilt" ]; then
|
||||
echo
|
||||
echo "Can not detect Android NDK toolchain. Please use -android-toolchain-version to specify"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$CFG_DEFAULT_ANDROID_NDK_HOST" ] || [ ! -d "$CFG_DEFAULT_ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION/prebuilt/$CFG_DEFAULT_ANDROID_NDK_HOST" ]; then
|
||||
echo
|
||||
echo "Can not detect the android host. Please use -android-ndk-host option to specify one"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
QT_QPA_DEFAULT_PLATFORM="android"
|
||||
CFG_LARGEFILE="no"
|
||||
|
||||
# FIXME: Qt Creator requires this to be in the lib/ directory of Qt. This line can be removed
|
||||
# once it's fixed to get the file directly from the NDK.
|
||||
cp -f $CFG_DEFAULT_ANDROID_NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION/libs/$CFG_DEFAULT_ANDROID_TARGET_ARCH/libgnustl_shared.so $outpath/lib
|
||||
|
||||
DeviceVar set DEFAULT_ANDROID_SDK_ROOT "$CFG_DEFAULT_ANDROID_SDK_ROOT"
|
||||
DeviceVar set DEFAULT_ANDROID_NDK_ROOT "$CFG_DEFAULT_ANDROID_NDK_ROOT"
|
||||
DeviceVar set DEFAULT_ANDROID_PLATFORM "$CFG_DEFAULT_ANDROID_PLATFORM"
|
||||
DeviceVar set DEFAULT_ANDROID_NDK_HOST "$CFG_DEFAULT_ANDROID_NDK_HOST"
|
||||
DeviceVar set DEFAULT_ANDROID_TARGET_ARCH "$CFG_DEFAULT_ANDROID_TARGET_ARCH"
|
||||
DeviceVar set DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION "$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d "$PLATFORM" ]; then
|
||||
QMAKESPEC="$PLATFORM"
|
||||
@ -2644,6 +2752,32 @@ fi
|
||||
QMAKE_CONF_COMPILER=`getXQMakeConf QMAKE_CXX`
|
||||
|
||||
TEST_COMPILER=$QMAKE_CONF_COMPILER
|
||||
|
||||
if [ "$OPT_HELP" != "yes" ] && [ "$XPLATFORM_ANDROID" = "yes" ] ; then
|
||||
ANDROID_NDK_TOOLS_PREFIX=
|
||||
ANDROID_PLATFORM_ARCH=
|
||||
case $CFG_DEFAULT_ANDROID_TARGET_ARCH in
|
||||
armeabi*)
|
||||
ANDROID_NDK_TOOLS_PREFIX=arm-linux-androideabi
|
||||
ANDROID_PLATFORM_ARCH=arch-arm
|
||||
;;
|
||||
x86)
|
||||
ANDROID_NDK_TOOLS_PREFIX=x86
|
||||
ANDROID_PLATFORM_ARCH=arch-x86
|
||||
;;
|
||||
mips)
|
||||
ANDROID_NDK_TOOLS_PREFIX=mipsel-linux-android
|
||||
ANDROID_PLATFORM_ARCH=arch-mips
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unknown android arch $CFG_DEFAULT_ANDROID_TARGET_ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
QMAKE_CONF_COMPILER=$CFG_DEFAULT_ANDROID_NDK_ROOT/toolchains/$ANDROID_NDK_TOOLS_PREFIX-$CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION/prebuilt/$CFG_DEFAULT_ANDROID_NDK_HOST/bin/$ANDROID_NDK_TOOLS_PREFIX-g++
|
||||
TEST_COMPILER="$QMAKE_CONF_COMPILER --sysroot=$CFG_DEFAULT_ANDROID_NDK_ROOT/platforms/$CFG_DEFAULT_ANDROID_PLATFORM/$ANDROID_PLATFORM_ARCH/"
|
||||
fi
|
||||
|
||||
if [ "$XPLATFORM_SYMBIAN_SBSV2" = "no" ]; then
|
||||
if [ -z "$TEST_COMPILER" ]; then
|
||||
echo "ERROR: Cannot set the compiler for the configuration tests"
|
||||
@ -3354,6 +3488,31 @@ Qt/Mac only:
|
||||
QT_ENABLE_HARFBUZZ environment variable.
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$XPLATFORM_ANDROID" = "yes" ]; then
|
||||
cat << EOF
|
||||
|
||||
Android options:
|
||||
-android-sdk path .............. The Android SDK root path.
|
||||
(default $CFG_DEFAULT_ANDROID_SDK_ROOT)
|
||||
|
||||
-android-ndk path .............. The Android NDK root path.
|
||||
(default $CFG_DEFAULT_ANDROID_NDK_ROOT)
|
||||
|
||||
-android-ndk-platform .......... Sets the android platform
|
||||
(default $CFG_DEFAULT_ANDROID_PLATFORM)
|
||||
|
||||
-android-ndk-host .............. Sets the android NDK host (linux-x86, linux-x86_64, etc.)
|
||||
(default $CFG_DEFAULT_ANDROID_NDK_HOST)
|
||||
|
||||
-android-arch .................. Sets the android architecture (armeabi, armeabi-v7a, x86, mips)
|
||||
(default $CFG_DEFAULT_ANDROID_TARGET_ARCH)
|
||||
|
||||
-android-toolchain-version ..... Sets the android toolchain version
|
||||
(default $CFG_DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION)
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
[ "x$ERROR" = "xyes" ] && exit 1
|
||||
@ -4079,6 +4238,7 @@ elif [ "$CFG_ARCH" != "mips" ]; then
|
||||
fi
|
||||
|
||||
[ "$XPLATFORM_MINGW" = "yes" ] && QMakeVar add styles "windowsxp windowsvista"
|
||||
[ "$XPLATFORM_ANDROID" = "yes" ] && QMakeVar add styles "android"
|
||||
|
||||
# detect zlib
|
||||
if [ "$CFG_ZLIB" = "no" ]; then
|
||||
@ -5088,7 +5248,7 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$BUILD_ON_MAC" = "no" ] && [ "$XPLATFORM_MINGW" = "no" ] && [ "$XPLATFORM_QNX" = "no" ]; then
|
||||
if [ "$BUILD_ON_MAC" = "no" ] && [ "$XPLATFORM_MINGW" = "no" ] && [ "$XPLATFORM_QNX" = "no" ] && [ "$XPLATFORM_ANDROID" = "no" ]; then
|
||||
if [ "$CFG_XCB" = "no" ] && [ "$CFG_EGLFS" = "no" ] && [ "$CFG_DIRECTFB" = "no" ] && [ "$CFG_LINUXFB" = "no" ] && [ "$CFG_KMS" = "no" ]; then
|
||||
if [ "$QPA_PLATFORM_GUARD" = "yes" ] &&
|
||||
( [ "$ORIG_CFG_XCB" = "auto" ] || [ "$ORIG_CFG_EGLFS" = "auto" ] || [ "$ORIG_CFG_DIRECTFB" = "auto" ] || [ "$ORIG_CFG_LINUXFB" = "auto" ] || [ "$ORIG_CFG_KMS" = "auto" ] ); then
|
||||
@ -5242,7 +5402,7 @@ if [ "$CFG_OPENSSL" != "no" ]; then
|
||||
CFG_OPENSSL=yes
|
||||
fi
|
||||
else
|
||||
if ( [ "$CFG_OPENSSL" = "yes" ] || [ "$CFG_OPENSSL" = "linked" ] ) && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then
|
||||
if ( [ "$CFG_OPENSSL" = "yes" ] || [ "$CFG_OPENSSL" = "linked" ] ) && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ] && [ "$XPLATFORM_ANDROID" = "no" ]; then
|
||||
echo "OpenSSL support cannot be enabled due to functionality tests!"
|
||||
echo " Turn on verbose messaging (-v) to $0 to see the final report."
|
||||
echo " If you believe this message is in error you may use the continue"
|
||||
|
178
mkspecs/android-g++/qmake.conf
Normal file
178
mkspecs/android-g++/qmake.conf
Normal file
@ -0,0 +1,178 @@
|
||||
# qmake configuration for building with android-g++
|
||||
MAKEFILE_GENERATOR = UNIX
|
||||
QMAKE_PLATFORM = android
|
||||
QMAKE_COMPILER = gcc
|
||||
|
||||
CONFIG += android_install
|
||||
DEFINES += QT_NO_PRINTDIALOG
|
||||
|
||||
include(../qdevice.pri)
|
||||
include(../common/linux.conf)
|
||||
include(../common/gcc-base-unix.conf)
|
||||
|
||||
# Passing in -win32 to qmake (from NQTC) causes this condition to pass, however
|
||||
# qmake complains that -win32 is deprecated; should find another way, Q_OS_WIN
|
||||
# should really be all QMAKE_HOST.os needs to depend on?
|
||||
contains(QMAKE_HOST.os,Windows) {
|
||||
# Not having sh.exe in your path causes this condition to pass
|
||||
# To build Android Qt on Windows, this block must not be evaluated.
|
||||
isEmpty(QMAKE_SH) {
|
||||
include(../common/shell-win32.conf)
|
||||
QMAKE_DEL_TREE = rmdir /s /q
|
||||
QMAKE_INSTALL_FILE = copy /y
|
||||
QMAKE_INSTALL_PROGRAM = copy /y
|
||||
}
|
||||
}
|
||||
|
||||
NDK_ROOT = $$(ANDROID_NDK_ROOT)
|
||||
!exists($$NDK_ROOT) {
|
||||
NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT
|
||||
!exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.")
|
||||
}
|
||||
|
||||
NDK_HOST = $$(ANDROID_NDK_HOST)
|
||||
isEmpty(NDK_HOST): NDK_HOST = $$DEFAULT_ANDROID_NDK_HOST
|
||||
|
||||
ANDROID_PLATFORM = $$(ANDROID_NDK_PLATFORM)
|
||||
isEmpty(ANDROID_PLATFORM): ANDROID_PLATFORM = $$DEFAULT_ANDROID_PLATFORM
|
||||
|
||||
ANDROID_TARGET_ARCH = $$(ANDROID_TARGET_ARCH)
|
||||
isEmpty(ANDROID_TARGET_ARCH): ANDROID_TARGET_ARCH = $$DEFAULT_ANDROID_TARGET_ARCH
|
||||
|
||||
NDK_TOOLCHAIN_PREFIX = $$(ANDROID_NDK_TOOLCHAIN_PREFIX)
|
||||
isEmpty(NDK_TOOLCHAIN_PREFIX) {
|
||||
equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLCHAIN_PREFIX = x86
|
||||
else: equals(ANDROID_TARGET_ARCH, mips): NDK_TOOLCHAIN_PREFIX = mipsel-linux-android
|
||||
else: NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi
|
||||
}
|
||||
|
||||
NDK_TOOLS_PREFIX = $$(ANDROID_NDK_TOOLS_PREFIX)
|
||||
isEmpty(NDK_TOOLS_PREFIX) {
|
||||
equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLS_PREFIX = i686-linux-android
|
||||
else: equals(ANDROID_TARGET_ARCH, mips): NDK_TOOLS_PREFIX = mipsel-linux-android
|
||||
else: NDK_TOOLS_PREFIX = arm-linux-androideabi
|
||||
}
|
||||
|
||||
NDK_TOOLCHAIN_VERSION = $$(ANDROID_NDK_TOOLCHAIN_VERSION)
|
||||
isEmpty(NDK_TOOLCHAIN_VERSION): NDK_TOOLCHAIN_VERSION = $$DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION
|
||||
|
||||
equals(ANDROID_TARGET_ARCH, x86): ANDROID_ARCHITECTURE = x86
|
||||
else: equals(ANDROID_TARGET_ARCH, mips): ANDROID_ARCHITECTURE = mips
|
||||
else: ANDROID_ARCHITECTURE = arm
|
||||
|
||||
!equals(NDK_TOOLCHAIN_VERSION, 4.4.3): ANDROID_CXXSTL_SUFFIX = -$$NDK_TOOLCHAIN_VERSION
|
||||
|
||||
NDK_TOOLCHAIN = $$NDK_TOOLCHAIN_PREFIX-$$NDK_TOOLCHAIN_VERSION
|
||||
NDK_TOOLCHAIN_PATH = $$NDK_ROOT/toolchains/$$NDK_TOOLCHAIN/prebuilt/$$NDK_HOST
|
||||
|
||||
CONFIG += $$ANDROID_PLATFORM
|
||||
ANDROID_PLATFORM_ROOT_PATH = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/
|
||||
ANDROID_PLATFORM_PATH = $$ANDROID_PLATFORM_ROOT_PATH/usr
|
||||
|
||||
# used to compile platform plugins for android-4 and android-5
|
||||
QMAKE_ANDROID_PLATFORM_INCDIR = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/usr/include
|
||||
QMAKE_ANDROID_PLATFORM_LIBDIR = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/usr/lib
|
||||
|
||||
ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/libs/$$ANDROID_TARGET_ARCH
|
||||
ANDROID_SOURCES_CXX_STL_INCDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/include $$ANDROID_SOURCES_CXX_STL_LIBDIR/include
|
||||
|
||||
# modifications to g++.conf
|
||||
QMAKE_CC = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX-gcc
|
||||
|
||||
equals(ANDROID_TARGET_ARCH, armeabi-v7a): \
|
||||
QMAKE_CFLAGS = -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -DANDROID -Wa,--noexecstack
|
||||
else: equals(ANDROID_TARGET_ARCH, armeabi): \
|
||||
QMAKE_CFLAGS = -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -DANDROID -Wa,--noexecstack
|
||||
else: equals(ANDROID_TARGET_ARCH, x86): \
|
||||
QMAKE_CFLAGS = -ffunction-sections -funwind-tables -O2 -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300 -DANDROID -Wa,--noexecstack
|
||||
else: equals(ANDROID_TARGET_ARCH, mips): \
|
||||
QMAKE_CFLAGS = -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers -O2 -fomit-frame-pointer -funswitch-loops -finline-limit=300 -DANDROID -Wa,--noexecstack
|
||||
|
||||
QMAKE_CFLAGS_WARN_ON = -Wall -Wno-psabi -W
|
||||
QMAKE_CFLAGS_WARN_OFF = -Wno-psabi
|
||||
equals(ANDROID_TARGET_ARCH, x86) {
|
||||
QMAKE_CFLAGS_RELEASE = -O2
|
||||
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = -g -O2
|
||||
QMAKE_CFLAGS_DEBUG = -g
|
||||
} else: equals(ANDROID_TARGET_ARCH, mips) {
|
||||
QMAKE_CFLAGS_RELEASE = -O2
|
||||
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = -g -O2
|
||||
QMAKE_CFLAGS_DEBUG = -g -fno-omit-frame-pointer
|
||||
} else { # arm
|
||||
QMAKE_CFLAGS_RELEASE = -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64
|
||||
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = -g -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64
|
||||
QMAKE_CFLAGS_DEBUG = -g -marm -O0 -fno-omit-frame-pointer
|
||||
}
|
||||
|
||||
QMAKE_CFLAGS_SHLIB = -fPIC
|
||||
QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses
|
||||
QMAKE_CFLAGS_THREAD = -D_REENTRANT
|
||||
QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden
|
||||
|
||||
QMAKE_CXX = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX-g++
|
||||
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS -std=gnu++0x
|
||||
QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON
|
||||
QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF
|
||||
QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE
|
||||
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
|
||||
QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG
|
||||
QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB
|
||||
QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC
|
||||
QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD
|
||||
QMAKE_CXXFLAGS_HIDESYMS = $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden
|
||||
|
||||
QMAKE_LINK = $$QMAKE_CXX
|
||||
QMAKE_LINK_SHLIB = $$QMAKE_LINK
|
||||
|
||||
# modifications to linux.conf
|
||||
QMAKE_AR = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX-ar cqs
|
||||
QMAKE_OBJCOPY = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX-objcopy
|
||||
|
||||
QMAKE_STRIP =
|
||||
#$$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX-strip
|
||||
|
||||
QMAKE_RANLIB = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX-ranlib
|
||||
|
||||
QMAKE_INCDIR = $$ANDROID_SOURCES_CXX_STL_INCDIR $$ANDROID_PLATFORM_PATH/include
|
||||
QMAKE_LIBDIR = $$ANDROID_SOURCES_CXX_STL_LIBDIR $$ANDROID_PLATFORM_PATH/lib $$LIBGCC_PATH
|
||||
QMAKE_INCDIR_X11 =
|
||||
QMAKE_LIBDIR_X11 =
|
||||
QMAKE_INCDIR_OPENGL = $$ANDROID_PLATFORM_PATH/include
|
||||
QMAKE_LIBDIR_OPENGL = $$ANDROID_PLATFORM_PATH/lib
|
||||
|
||||
equals(ANDROID_TARGET_ARCH, x86)|equals(ANDROID_TARGET_ARCH, mips): \
|
||||
LIBGCC_PATH_FULL = $$system("$$QMAKE_CC -print-libgcc-file-name")
|
||||
else: \
|
||||
LIBGCC_PATH_FULL = $$system("$$QMAKE_CC -mthumb-interwork -print-libgcc-file-name")
|
||||
|
||||
LIBGCC_PATH = $$dirname(LIBGCC_PATH_FULL)
|
||||
|
||||
QMAKE_LINK = $$QMAKE_CXX
|
||||
QMAKE_LINK_SHLIB = $$QMAKE_CXX
|
||||
QMAKE_LFLAGS = --sysroot=$$ANDROID_PLATFORM_ROOT_PATH
|
||||
QMAKE_RPATHLINK = $$ANDROID_PLATFORM_PATH/lib
|
||||
QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared
|
||||
QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared
|
||||
|
||||
contains(NDK_ROOT, ".*r6")|contains(NDK_ROOT, ".*r5.*") {
|
||||
!equals(ANDROID_PLATFORM, android-4):!equals(ANDROID_PLATFORM, android-5):!equals(ANDROID_PLATFORM, android-8) {
|
||||
warning("Your NDK version is outdated. A workaround is enabled. Consider updating your NDK (workarounds are required until r6(a))")
|
||||
QMAKE_LFLAGS_SHLIB += $$ANDROID_PLATFORM_PATH/lib/crtbegin_so.o $$ANDROID_PLATFORM_PATH/lib/crtend_so.o
|
||||
}
|
||||
}
|
||||
|
||||
QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB
|
||||
QMAKE_LFLAGS_SONAME =
|
||||
QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined
|
||||
QMAKE_LFLAGS_RPATH = -Wl,-rpath=
|
||||
QMAKE_LFLAGS_RPATHLINK = -Wl,-rpath-link=
|
||||
|
||||
QMAKE_LIBS = -lgnustl_shared -lsupc++ -llog -lz -lm -ldl -lc -lgcc
|
||||
QMAKE_LIBS_X11 =
|
||||
QMAKE_LIBS_THREAD =
|
||||
QMAKE_LIBS_EGL = -lEGL
|
||||
QMAKE_LIBS_OPENGL =
|
||||
QMAKE_LIBS_OPENGL_ES1 = -lGLESv1_CM
|
||||
QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 $$QMAKE_LIBS
|
||||
|
||||
load(qt_config)
|
187
mkspecs/android-g++/qplatformdefs.h
Normal file
187
mkspecs/android-g++/qplatformdefs.h
Normal file
@ -0,0 +1,187 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the qmake spec 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QPLATFORMDEFS_H
|
||||
#define QPLATFORMDEFS_H
|
||||
|
||||
#define QT_QPA_DEFAULT_PLATFORM_NAME "android"
|
||||
|
||||
// Get Qt defines/settings
|
||||
|
||||
#include "qglobal.h"
|
||||
|
||||
// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs
|
||||
|
||||
// 1) need to reset default environment if _BSD_SOURCE is defined
|
||||
// 2) need to specify POSIX thread interfaces explicitly in glibc 2.0
|
||||
// 3) it seems older glibc need this to include the X/Open stuff
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// We are hot - unistd.h should have turned on the specific APIs we requested
|
||||
|
||||
#include <features.h>
|
||||
#include <pthread.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifndef QT_NO_IPV6IFNAME
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#ifdef QT_LARGEFILE_SUPPORT
|
||||
#define QT_STATBUF struct stat64
|
||||
#define QT_STATBUF4TSTAT struct stat64
|
||||
#define QT_STAT ::stat64
|
||||
#define QT_FSTAT ::fstat64
|
||||
#define QT_LSTAT ::lstat64
|
||||
#define QT_OPEN ::open64
|
||||
#define QT_TRUNCATE ::truncate64
|
||||
#define QT_FTRUNCATE ::ftruncate64
|
||||
#define QT_LSEEK ::lseek64
|
||||
#else
|
||||
#define QT_STATBUF struct stat
|
||||
#define QT_STATBUF4TSTAT struct stat
|
||||
#define QT_STAT ::stat
|
||||
#define QT_FSTAT ::fstat
|
||||
#define QT_LSTAT ::lstat
|
||||
#define QT_OPEN ::open
|
||||
#define QT_TRUNCATE ::truncate
|
||||
#define QT_FTRUNCATE ::ftruncate
|
||||
#define QT_LSEEK ::lseek
|
||||
#endif
|
||||
|
||||
#ifdef QT_LARGEFILE_SUPPORT
|
||||
#define QT_FOPEN ::fopen64
|
||||
#define QT_FSEEK ::fseeko64
|
||||
#define QT_FTELL ::ftello64
|
||||
#define QT_FGETPOS ::fgetpos64
|
||||
#define QT_FSETPOS ::fsetpos64
|
||||
#define QT_MMAP ::mmap64
|
||||
#define QT_FPOS_T fpos64_t
|
||||
#define QT_OFF_T off64_t
|
||||
#else
|
||||
#define QT_FOPEN ::fopen
|
||||
#define QT_FSEEK ::fseek
|
||||
#define QT_FTELL ::ftell
|
||||
#define QT_FGETPOS ::fgetpos
|
||||
#define QT_FSETPOS ::fsetpos
|
||||
#define QT_MMAP ::mmap
|
||||
#define QT_FPOS_T fpos_t
|
||||
#define QT_OFF_T long
|
||||
#endif
|
||||
|
||||
#define QT_STAT_REG S_IFREG
|
||||
#define QT_STAT_DIR S_IFDIR
|
||||
#define QT_STAT_MASK S_IFMT
|
||||
#define QT_STAT_LNK S_IFLNK
|
||||
#define QT_SOCKET_CONNECT ::connect
|
||||
#define QT_SOCKET_BIND ::bind
|
||||
#define QT_FILENO fileno
|
||||
#define QT_CLOSE ::close
|
||||
#define QT_READ ::read
|
||||
#define QT_WRITE ::write
|
||||
#define QT_ACCESS ::access
|
||||
#define QT_GETCWD ::getcwd
|
||||
#define QT_CHDIR ::chdir
|
||||
#define QT_MKDIR ::mkdir
|
||||
#define QT_RMDIR ::rmdir
|
||||
#define QT_OPEN_LARGEFILE O_LARGEFILE
|
||||
#define QT_OPEN_RDONLY O_RDONLY
|
||||
#define QT_OPEN_WRONLY O_WRONLY
|
||||
#define QT_OPEN_RDWR O_RDWR
|
||||
#define QT_OPEN_CREAT O_CREAT
|
||||
#define QT_OPEN_TRUNC O_TRUNC
|
||||
#define QT_OPEN_APPEND O_APPEND
|
||||
|
||||
// Directory iteration
|
||||
#define QT_DIR DIR
|
||||
|
||||
#define QT_OPENDIR ::opendir
|
||||
#define QT_CLOSEDIR ::closedir
|
||||
|
||||
#if defined(QT_LARGEFILE_SUPPORT) \
|
||||
&& defined(QT_USE_XOPEN_LFS_EXTENSIONS) \
|
||||
&& !defined(QT_NO_READDIR64)
|
||||
#define QT_DIRENT struct dirent64
|
||||
#define QT_READDIR ::readdir64
|
||||
#define QT_READDIR_R ::readdir64_r
|
||||
#else
|
||||
#define QT_DIRENT struct dirent
|
||||
#define QT_READDIR ::readdir
|
||||
#define QT_READDIR_R ::readdir_r
|
||||
#endif
|
||||
|
||||
#define QT_SOCKET_CONNECT ::connect
|
||||
#define QT_SOCKET_BIND ::bind
|
||||
|
||||
|
||||
#define QT_SIGNAL_RETTYPE void
|
||||
#define QT_SIGNAL_ARGS int
|
||||
#define QT_SIGNAL_IGNORE SIG_IGN
|
||||
|
||||
#if defined(__GLIBC__) && (__GLIBC__ >= 2)
|
||||
#define QT_SOCKLEN_T socklen_t
|
||||
#else
|
||||
#define QT_SOCKLEN_T int
|
||||
#endif
|
||||
|
||||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)
|
||||
#define QT_SNPRINTF ::snprintf
|
||||
#define QT_VSNPRINTF ::vsnprintf
|
||||
#endif
|
||||
|
||||
#endif // QPLATFORMDEFS_H
|
14
mkspecs/features/android.prf
Normal file
14
mkspecs/features/android.prf
Normal file
@ -0,0 +1,14 @@
|
||||
contains(TEMPLATE, ".*app") {
|
||||
!android_app {
|
||||
!contains(TARGET, ".so"): TARGET = lib$${TARGET}.so
|
||||
QMAKE_LFLAGS += -Wl,-soname,$$TARGET
|
||||
}
|
||||
}
|
||||
!QTDIR_build:android_install {
|
||||
isEmpty(QT_BUILD_TREE) {
|
||||
target.path=/libs/$$ANDROID_TARGET_ARCH/
|
||||
} else {
|
||||
target.path = /
|
||||
}
|
||||
INSTALLS *= target
|
||||
}
|
61
mkspecs/features/java.prf
Normal file
61
mkspecs/features/java.prf
Normal file
@ -0,0 +1,61 @@
|
||||
TEMPLATE = lib
|
||||
android {
|
||||
isEmpty(SDK_ROOT): SDK_ROOT = $$(ANDROID_SDK_ROOT)
|
||||
isEmpty(SDK_ROOT): SDK_ROOT = $$DEFAULT_ANDROID_SDK_ROOT
|
||||
isEmpty(API_VERSION) {
|
||||
API_VERSION = $$(ANDROID_API_VERSION)
|
||||
isEmpty(API_VERSION): API_VERSION = android-10
|
||||
}
|
||||
|
||||
!exists($$SDK_ROOT/platforms/$$API_VERSION/android.jar) {
|
||||
error("The Path $$SDK_ROOT/platforms/$$API_VERSION/android.jar does not exist. Make sure the ANDROID_SDK_ROOT and ANDROID_API_VERSION environment variables are correctly set.")
|
||||
}
|
||||
JAVACLASSPATH += $$SDK_ROOT/platforms/$$API_VERSION/android.jar
|
||||
|
||||
# FIXME: This is a hack to work around some hardcoded values in the android.prf. The
|
||||
# android.prf should be fixed and this should be removed.
|
||||
CONFIG += android_app
|
||||
}
|
||||
|
||||
isEmpty(CLASS_DIR): CLASS_DIR = .classes
|
||||
|
||||
CONFIG -= qt
|
||||
|
||||
# Without these, qmake adds a name prefix and versioning postfixes (as well as file
|
||||
# links) to the target. This is hardcoded in the qmake code, so for now we use
|
||||
# the plugin configs to get what we want.
|
||||
CONFIG += plugin no_plugin_name_prefix
|
||||
|
||||
javac.input = JAVASOURCES
|
||||
javac.output = $$CLASS_DIR
|
||||
javac.CONFIG += combine
|
||||
javac.commands = javac -source 6 -target 6 -cp $$shell_quote($$join(JAVACLASSPATH, ":")) -d $$shell_quote($$CLASS_DIR) ${QMAKE_FILE_IN}
|
||||
# Force rebuild every time, because we don't know the paths of the destination files
|
||||
# as they depend on the code.
|
||||
javac.depends = FORCE
|
||||
QMAKE_EXTRA_COMPILERS += javac
|
||||
|
||||
mkpath($$absolute_path($$CLASS_DIR, $$OUT_PWD)) | error("Aborting.")
|
||||
|
||||
# Disable all linker flags since we are overriding the regular linker
|
||||
QMAKE_LFLAGS =
|
||||
QMAKE_CFLAGS =
|
||||
QMAKE_LFLAGS_RPATH =
|
||||
QMAKE_LFLAGS_PLUGIN =
|
||||
QMAKE_LIBS =
|
||||
QMAKE_LIBS_OPENGL_ES2 =
|
||||
QMAKE_LIBDIR =
|
||||
QMAKE_EXTENSION_SHLIB = jar
|
||||
|
||||
# Override linker with dex (for Android) or jar (for other java builds)
|
||||
android {
|
||||
QMAKE_LINK_O_FLAG = --output=
|
||||
QMAKE_LINK = $$SDK_ROOT/platform-tools/dx --dex
|
||||
} else {
|
||||
QMAKE_LINK_O_FLAG = "cf "
|
||||
QMAKE_LINK = jar
|
||||
}
|
||||
|
||||
# Force link step to always happen, since we are always updating the
|
||||
# .class files
|
||||
PRE_TARGETDEPS += FORCE
|
@ -2,7 +2,7 @@ CONFIG += qpa/basicunixfontdatabase
|
||||
contains(QT_CONFIG, fontconfig) {
|
||||
DEFINES += Q_FONTCONFIGDATABASE
|
||||
LIBS += -lfontconfig
|
||||
} else {
|
||||
} else:!android {
|
||||
fonts.path = $$[QT_INSTALL_LIBS]/fonts
|
||||
fonts.files = $$QT_SOURCE_TREE/lib/fonts/*
|
||||
INSTALLS += fonts
|
||||
|
53
mkspecs/features/qt_android_deps.prf
Normal file
53
mkspecs/features/qt_android_deps.prf
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
# W A R N I N G
|
||||
# -------------
|
||||
#
|
||||
# This file is not part of the Qt API. It exists purely as an
|
||||
# implementation detail. It may change from version to version
|
||||
# without notice, or even be removed.
|
||||
#
|
||||
# We mean it.
|
||||
#
|
||||
|
||||
# Generates an xml file to match the library in lib/ listing the dependencies
|
||||
# of the module on JNI-based libraries etc. Used for deployment of an Android
|
||||
# app.
|
||||
|
||||
ANDROID_DEPENDS_DIR = $$MODULE_QMAKE_OUTDIR/lib/
|
||||
DEPENDENCY_FILE = $$ANDROID_DEPENDS_DIR$$TARGET-android-dependencies.xml
|
||||
|
||||
!build_pass {
|
||||
!isEmpty(ANDROID_JAR_DEPENDENCIES) {
|
||||
for(JAR_FILE, ANDROID_JAR_DEPENDENCIES) {
|
||||
INIT_CLASS = $$section(JAR_FILE, ":", 1, 1)
|
||||
!isEmpty(INIT_CLASS): INIT_CLASS = "initClass=\"$$INIT_CLASS\""
|
||||
JAR_FILE = $$section(JAR_FILE, ":", 0, 0)
|
||||
FILE_CONTENT += "<jar file=\"$$JAR_FILE\" $$INIT_CLASS />"
|
||||
}
|
||||
}
|
||||
|
||||
!isEmpty(ANDROID_LIB_DEPENDENCIES) {
|
||||
for(LIB_FILE, ANDROID_LIB_DEPENDENCIES) {
|
||||
FILE_CONTENT += "<lib file=\"$$LIB_FILE\" />"
|
||||
}
|
||||
}
|
||||
|
||||
!isEmpty(ANDROID_LIB_DEPENDENCY_REPLACEMENTS) {
|
||||
for(REPLACEMENT, ANDROID_LIB_DEPENDENCY_REPLACEMENTS) {
|
||||
REPLACEMENT_FILE = $$section(REPLACEMENT, ":", 0, 0)
|
||||
LIB_FILE = $$section(REPLACEMENT, ":", 1, 1)
|
||||
FILE_CONTENT += "<lib file=\"$$LIB_FILE\" replaces=\"$$REPLACEMENT_FILE\" />"
|
||||
}
|
||||
}
|
||||
|
||||
!isEmpty(FILE_CONTENT) {
|
||||
FILE_CONTENT = "<rules><dependencies><lib name=\"$$TARGET\"><depends>" $$FILE_CONTENT "</depends></lib></dependencies></rules>"
|
||||
write_file($$DEPENDENCY_FILE, FILE_CONTENT) | error("Aborting.")
|
||||
}
|
||||
}
|
||||
|
||||
!isEmpty(ANDROID_JAR_DEPENDENCIES)|!isEmpty(ANDROID_LIB_DEPENDENCIES)|!isEmpty(ANDROID_LIB_DEPENDENCY_REPLACEMENTS) {
|
||||
install_dependencies_file.files = $$DEPENDENCY_FILE
|
||||
install_dependencies_file.path = $$[QT_INSTALL_LIBS]
|
||||
INSTALLS += install_dependencies_file
|
||||
}
|
@ -107,6 +107,8 @@ aix-g++* {
|
||||
QMAKE_CXXFLAGS += -mminimal-toc
|
||||
}
|
||||
|
||||
android: CONFIG += qt_android_deps
|
||||
|
||||
#install directives
|
||||
load(qt_installs)
|
||||
|
||||
|
@ -174,7 +174,7 @@ QMAKE_LIBS_OPENGL =
|
||||
QMAKE_LIBS_OPENGL_ES1 = -lGLESv1_CM
|
||||
QMAKE_LIBS_OPENGL_ES2 = -lEGL -lGLESv2 $$QMAKE_LIBS
|
||||
|
||||
CONFIG += linux-android-9 android-9 linux-android android
|
||||
CONFIG += linux-android-9 android-9 linux-android android android-no-sdk android_app
|
||||
|
||||
load(qt_config)
|
||||
QT_CONFIG -=accessibility
|
||||
|
@ -1,14 +0,0 @@
|
||||
#
|
||||
# qmake configuration for building with android-g++ for ARMv5
|
||||
#
|
||||
|
||||
ANDROID_TARGET_ARCH = armeabi
|
||||
ANDROID_ARCHITECTURE = arm
|
||||
ANDROID_NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi
|
||||
ANDROID_NDK_TOOLS_PREFIX = arm-linux-androideabi
|
||||
QMAKE_CFLAGS = -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -DANDROID -Wa,--noexecstack
|
||||
QMAKE_CFLAGS_RELEASE = -g -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64
|
||||
QMAKE_CFLAGS_DEBUG = -g -marm -O0 -fno-omit-frame-pointer
|
||||
|
||||
include(../../common/linux-android.conf)
|
||||
|
@ -1,14 +0,0 @@
|
||||
#
|
||||
# qmake configuration for building with android-g++ for ARMv7
|
||||
#
|
||||
|
||||
ANDROID_TARGET_ARCH = armeabi-v7a
|
||||
ANDROID_ARCHITECTURE = arm
|
||||
ANDROID_NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi
|
||||
ANDROID_NDK_TOOLS_PREFIX = arm-linux-androideabi
|
||||
QMAKE_CFLAGS = -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -DANDROID -Wa,--noexecstack
|
||||
QMAKE_CFLAGS_RELEASE = -g -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64
|
||||
QMAKE_CFLAGS_DEBUG = -g -marm -O0 -fno-omit-frame-pointer
|
||||
|
||||
include(../../common/linux-android.conf)
|
||||
|
@ -1,14 +0,0 @@
|
||||
#
|
||||
# qmake configuration for building with android-g++ for x86
|
||||
#
|
||||
|
||||
ANDROID_TARGET_ARCH = x86
|
||||
ANDROID_ARCHITECTURE = x86
|
||||
ANDROID_NDK_TOOLCHAIN_PREFIX = x86
|
||||
ANDROID_NDK_TOOLS_PREFIX = i686-android-linux
|
||||
QMAKE_CFLAGS = -ffunction-sections -funwind-tables -O2 -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300 -DANDROID -Wa,--noexecstack
|
||||
QMAKE_CFLAGS_RELEASE = -g -O2
|
||||
QMAKE_CFLAGS_DEBUG = -g
|
||||
|
||||
include(../../common/linux-android.conf)
|
||||
|
15
src/android/android.pro
Normal file
15
src/android/android.pro
Normal file
@ -0,0 +1,15 @@
|
||||
CONFIG += java
|
||||
TARGET = QtAndroid
|
||||
DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
|
||||
|
||||
PATHPREFIX = $$PWD/jar/src/org/qtproject/qt5/android/
|
||||
|
||||
JAVACLASSPATH += $$PWD/jar/src/
|
||||
JAVASOURCES += \
|
||||
$$PATHPREFIX/QtActivityDelegate.java \
|
||||
$$PATHPREFIX/QtEditText.java \
|
||||
$$PATHPREFIX/QtInputConnection.java \
|
||||
$$PATHPREFIX/QtLayout.java \
|
||||
$$PATHPREFIX/QtNative.java \
|
||||
$$PATHPREFIX/QtNativeLibrariesDir.java \
|
||||
$$PATHPREFIX/QtSurface.java
|
4
src/android/jar/AndroidManifest.xml
Normal file
4
src/android/jar/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="org.qtproject.qt5.android">
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
</manifest>
|
4
src/android/jar/res/values/strings.xml
Normal file
4
src/android/jar/res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">QtJar</string>
|
||||
</resources>
|
@ -0,0 +1,714 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
package org.qtproject.qt5.android;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.MetaKeyKeyListener;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
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.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
public class QtActivityDelegate
|
||||
{
|
||||
private Activity m_activity = null;
|
||||
private Method m_super_dispatchKeyEvent = null;
|
||||
private Method m_super_onRestoreInstanceState = null;
|
||||
private Method m_super_onRetainNonConfigurationInstance = null;
|
||||
private Method m_super_onSaveInstanceState = null;
|
||||
private Method m_super_onKeyDown = null;
|
||||
private Method m_super_onKeyUp = null;
|
||||
private Method m_super_onConfigurationChanged = null;
|
||||
|
||||
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 NECESSITAS_API_LEVEL_KEY = "necessitas.api.level";
|
||||
|
||||
private static String m_environmentVariables = null;
|
||||
private static String m_applicationParameters = null;
|
||||
|
||||
private int m_currentOrientation = Configuration.ORIENTATION_UNDEFINED;
|
||||
|
||||
private String m_mainLib;
|
||||
private long m_metaState;
|
||||
private int m_lastChar = 0;
|
||||
private boolean m_fullScreen = false;
|
||||
private boolean m_started = false;
|
||||
private QtSurface m_surface = null;
|
||||
private QtLayout m_layout = null;
|
||||
private QtEditText m_editText = null;
|
||||
private InputMethodManager m_imm = null;
|
||||
private boolean m_quitApp = true;
|
||||
private Process m_debuggerProcess = null; // debugger process
|
||||
|
||||
public boolean m_keyboardIsVisible = false;
|
||||
public boolean m_keyboardIsHiding = false;
|
||||
|
||||
public QtLayout getQtLayout()
|
||||
{
|
||||
return m_layout;
|
||||
}
|
||||
|
||||
public QtSurface getQtSurface()
|
||||
{
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
public void redrawWindow(int left, int top, int right, int bottom)
|
||||
{
|
||||
m_surface.drawBitmap(new Rect(left, top, right, bottom));
|
||||
}
|
||||
|
||||
public void setFullScreen(boolean enterFullScreen)
|
||||
{
|
||||
if (m_fullScreen == enterFullScreen)
|
||||
return;
|
||||
|
||||
if (m_fullScreen = enterFullScreen) {
|
||||
m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
||||
} else {
|
||||
m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
||||
m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
|
||||
// case status
|
||||
private final int ImhNoAutoUppercase = 0x2;
|
||||
private final int ImhPreferUppercase = 0x8;
|
||||
@SuppressWarnings("unused")
|
||||
private final int ImhPreferLowercase = 0x10;
|
||||
private final int ImhUppercaseOnly = 0x40000;
|
||||
private final int ImhLowercaseOnly = 0x80000;
|
||||
|
||||
// options
|
||||
private final int ImhNoPredictiveText = 0x20;
|
||||
|
||||
// layout
|
||||
private final int ImhHiddenText = 0x1;
|
||||
private final int ImhPreferNumbers = 0x4;
|
||||
private final int ImhMultiLine = 0x400;
|
||||
private final int ImhDigitsOnly = 0x10000;
|
||||
private final int ImhFormattedNumbersOnly = 0x20000;
|
||||
private final int ImhDialableCharactersOnly = 0x100000;
|
||||
private final int ImhEmailCharactersOnly = 0x200000;
|
||||
private final int ImhUrlCharactersOnly = 0x400000;
|
||||
|
||||
public void resetSoftwareKeyboard()
|
||||
{
|
||||
if (m_imm == null)
|
||||
return;
|
||||
m_editText.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_imm.restartInput(m_editText);
|
||||
}
|
||||
}, 5);
|
||||
}
|
||||
|
||||
public void showSoftwareKeyboard(int x, int y, int width, int height, int inputHints)
|
||||
{
|
||||
if (m_imm == null)
|
||||
return;
|
||||
if (height > m_surface.getHeight()*2/3)
|
||||
m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
else
|
||||
m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
|
||||
|
||||
int initialCapsMode = 0;
|
||||
int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||
int inputType = android.text.InputType.TYPE_CLASS_TEXT;
|
||||
|
||||
if ((inputHints & ImhMultiLine) != 0) {
|
||||
inputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
||||
}
|
||||
|
||||
if (((inputHints & ImhNoAutoUppercase) != 0 || (inputHints & ImhPreferUppercase) != 0)
|
||||
&& (inputHints & ImhLowercaseOnly) == 0) {
|
||||
initialCapsMode = android.text.TextUtils.CAP_MODE_SENTENCES;
|
||||
}
|
||||
|
||||
if ((inputHints & ImhUppercaseOnly) != 0)
|
||||
initialCapsMode = android.text.TextUtils.CAP_MODE_CHARACTERS;
|
||||
|
||||
if ((inputHints & ImhHiddenText) != 0)
|
||||
inputType = android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
||||
|
||||
if ((inputHints & ImhPreferNumbers) != 0)
|
||||
inputType = android.text.InputType.TYPE_CLASS_NUMBER;
|
||||
|
||||
if ((inputHints & ImhDigitsOnly) != 0)
|
||||
inputType = android.text.InputType.TYPE_CLASS_NUMBER;
|
||||
|
||||
if ((inputHints & ImhFormattedNumbersOnly) != 0) {
|
||||
inputType = android.text.InputType.TYPE_CLASS_NUMBER
|
||||
| android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL
|
||||
| android.text.InputType.TYPE_NUMBER_FLAG_SIGNED;
|
||||
}
|
||||
|
||||
if ((inputHints & ImhDialableCharactersOnly) != 0)
|
||||
inputType = android.text.InputType.TYPE_CLASS_PHONE;
|
||||
|
||||
if ((inputHints & ImhEmailCharactersOnly) != 0)
|
||||
inputType = android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
|
||||
|
||||
if ((inputHints & ImhUrlCharactersOnly) != 0) {
|
||||
inputType = android.text.InputType.TYPE_TEXT_VARIATION_URI;
|
||||
imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
|
||||
}
|
||||
|
||||
if ((inputHints & ImhNoPredictiveText) != 0) {
|
||||
//android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | android.text.InputType.TYPE_CLASS_TEXT;
|
||||
inputType = android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
|
||||
}
|
||||
|
||||
m_editText.setInitialCapsMode(initialCapsMode);
|
||||
m_editText.setImeOptions(imeOptions);
|
||||
m_editText.setInputType(inputType);
|
||||
|
||||
m_layout.removeView(m_editText);
|
||||
m_layout.addView(m_editText, new QtLayout.LayoutParams(width, height, x, y));
|
||||
m_editText.bringToFront();
|
||||
m_editText.requestFocus();
|
||||
m_editText.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_imm.showSoftInput(m_editText, 0);
|
||||
m_keyboardIsVisible = true;
|
||||
m_keyboardIsHiding = false;
|
||||
m_editText.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_imm.restartInput(m_editText);
|
||||
}
|
||||
}, 25);
|
||||
}
|
||||
}, 15);
|
||||
}
|
||||
|
||||
public void hideSoftwareKeyboard()
|
||||
{
|
||||
if (m_imm == null)
|
||||
return;
|
||||
m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0);
|
||||
m_keyboardIsVisible = false;
|
||||
m_keyboardIsHiding = false;
|
||||
}
|
||||
|
||||
public boolean isSoftwareKeyboardVisible()
|
||||
{
|
||||
return m_keyboardIsVisible;
|
||||
}
|
||||
|
||||
String getAppIconSize(Activity a)
|
||||
{
|
||||
int size = a.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
|
||||
if (size < 36 || size > 512) { // check size sanity
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
a.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
size = metrics.densityDpi/10*3;
|
||||
if (size < 36)
|
||||
size = 36;
|
||||
|
||||
if (size > 512)
|
||||
size = 512;
|
||||
}
|
||||
return "\tQT_ANDROID_APP_ICON_SIZE=" + size;
|
||||
}
|
||||
|
||||
public void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
|
||||
{
|
||||
if (m_imm == null)
|
||||
return;
|
||||
|
||||
m_imm.updateSelection(m_editText, selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
}
|
||||
|
||||
public boolean loadApplication(Activity activity, ClassLoader classLoader, Bundle loaderParams)
|
||||
{
|
||||
/// check parameters integrity
|
||||
if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY)
|
||||
|| !loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)
|
||||
|| !loaderParams.containsKey(ENVIRONMENT_VARIABLES_KEY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_activity = activity;
|
||||
QtNative.setActivity(m_activity, this);
|
||||
QtNative.setClassLoader(classLoader);
|
||||
if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) {
|
||||
for (String className: loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY)) {
|
||||
if (className.length() == 0)
|
||||
continue;
|
||||
|
||||
try {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class initClass = classLoader.loadClass(className);
|
||||
Object staticInitDataObject = initClass.newInstance(); // create an instance
|
||||
Method m = initClass.getMethod("setActivity", Activity.class, Object.class);
|
||||
m.invoke(staticInitDataObject, m_activity, 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_activity));
|
||||
m_mainLib = loaderParams.getString(MAIN_LIBRARY_KEY);
|
||||
// older apps provide the main library as the last bundled library; look for this if the main library isn't provided
|
||||
if (null == m_mainLib && libraries.size() > 0)
|
||||
m_mainLib = libraries.get(libraries.size() - 1);
|
||||
|
||||
try {
|
||||
m_super_dispatchKeyEvent = m_activity.getClass().getMethod("super_dispatchKeyEvent", KeyEvent.class);
|
||||
m_super_onRestoreInstanceState = m_activity.getClass().getMethod("super_onRestoreInstanceState", Bundle.class);
|
||||
m_super_onRetainNonConfigurationInstance = m_activity.getClass().getMethod("super_onRetainNonConfigurationInstance");
|
||||
m_super_onSaveInstanceState = m_activity.getClass().getMethod("super_onSaveInstanceState", Bundle.class);
|
||||
m_super_onKeyDown = m_activity.getClass().getMethod("super_onKeyDown", Integer.TYPE, KeyEvent.class);
|
||||
m_super_onKeyUp = m_activity.getClass().getMethod("super_onKeyUp", Integer.TYPE, KeyEvent.class);
|
||||
m_super_onConfigurationChanged = m_activity.getClass().getMethod("super_onConfigurationChanged", Configuration.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
int necessitasApiLevel = 1;
|
||||
if (loaderParams.containsKey(NECESSITAS_API_LEVEL_KEY))
|
||||
necessitasApiLevel = loaderParams.getInt(NECESSITAS_API_LEVEL_KEY);
|
||||
|
||||
m_environmentVariables = loaderParams.getString(ENVIRONMENT_VARIABLES_KEY);
|
||||
String additionalEnvironmentVariables = "QT_ANDROID_FONTS_MONOSPACE=Droid Sans Mono;Droid Sans;Droid Sans Fallback"
|
||||
+ "\tNECESSITAS_API_LEVEL=" + necessitasApiLevel
|
||||
+ "\tHOME=" + m_activity.getFilesDir().getAbsolutePath()
|
||||
+ "\tTMPDIR=" + m_activity.getFilesDir().getAbsolutePath();
|
||||
if (android.os.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";
|
||||
|
||||
additionalEnvironmentVariables += getAppIconSize(activity);
|
||||
|
||||
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 {
|
||||
// FIXME turn on debuggable check
|
||||
// if the applications is debuggable and it has a native debug request
|
||||
Bundle extras = m_activity.getIntent().getExtras();
|
||||
if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
|
||||
&&*/ extras != null
|
||||
&& extras.containsKey("native_debug")
|
||||
&& extras.getString("native_debug").equals("true")) {
|
||||
try {
|
||||
String packagePath =
|
||||
m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(),
|
||||
PackageManager.GET_CONFIGURATIONS).dataDir + "/";
|
||||
String gdbserverPath =
|
||||
extras.containsKey("gdbserver_path")
|
||||
? extras.getString("gdbserver_path")
|
||||
: packagePath+"lib/gdbserver ";
|
||||
|
||||
String socket =
|
||||
extras.containsKey("gdbserver_socket")
|
||||
? extras.getString("gdbserver_socket")
|
||||
: "+debug-socket";
|
||||
|
||||
// start debugger
|
||||
m_debuggerProcess = Runtime.getRuntime().exec(gdbserverPath
|
||||
+ socket
|
||||
+ " --attach "
|
||||
+ android.os.Process.myPid(),
|
||||
null,
|
||||
new File(packagePath));
|
||||
} catch (IOException ioe) {
|
||||
Log.e(QtNative.QtTAG,"Can't start debugger" + ioe.getMessage());
|
||||
} catch (SecurityException se) {
|
||||
Log.e(QtNative.QtTAG,"Can't start debugger" + se.getMessage());
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(QtNative.QtTAG,"Can't start debugger" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
|
||||
&&*/ extras != null
|
||||
&& extras.containsKey("debug_ping")
|
||||
&& extras.getString("debug_ping").equals("true")) {
|
||||
String packagePath =
|
||||
m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(),
|
||||
PackageManager.GET_CONFIGURATIONS).dataDir + "/";
|
||||
String debugPing = packagePath + "debug_ping";
|
||||
int i = 0;
|
||||
while (true) {
|
||||
++i;
|
||||
Log.i(QtNative.QtTAG, "DEBUGGER: WAITING FOR PING AT " + debugPing + ", ATTEMPT " + i);
|
||||
File file = new File(debugPing);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
break;
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
Log.i(QtNative.QtTAG, "DEBUGGER: GOT PING " + debugPing);
|
||||
}
|
||||
|
||||
|
||||
if (/*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0
|
||||
&&*/ extras != null
|
||||
&& extras.containsKey("qml_debug")
|
||||
&& extras.getString("qml_debug").equals("true")) {
|
||||
String qmljsdebugger;
|
||||
if (extras.containsKey("qmljsdebugger")) {
|
||||
qmljsdebugger = extras.getString("qmljsdebugger");
|
||||
qmljsdebugger.replaceAll("\\s", ""); // remove whitespace for security
|
||||
} else {
|
||||
qmljsdebugger = "port:3768";
|
||||
}
|
||||
m_applicationParameters += "\t-qmljsdebugger=" + qmljsdebugger;
|
||||
}
|
||||
|
||||
if (null == m_surface)
|
||||
onCreate(null);
|
||||
String nativeLibraryDir = QtNativeLibrariesDir.nativeLibrariesDir(m_activity);
|
||||
m_surface.applicationStarted( QtNative.startApplication(m_applicationParameters,
|
||||
m_environmentVariables,
|
||||
m_mainLib,
|
||||
nativeLibraryDir));
|
||||
m_started = true;
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void onTerminate()
|
||||
{
|
||||
QtNative.terminateQt();
|
||||
}
|
||||
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
m_quitApp = true;
|
||||
if (null == savedInstanceState) {
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
QtNative.setApplicationDisplayMetrics(metrics.widthPixels, metrics.heightPixels,
|
||||
metrics.widthPixels, metrics.heightPixels,
|
||||
metrics.xdpi, metrics.ydpi);
|
||||
}
|
||||
m_layout = new QtLayout(m_activity);
|
||||
m_surface = new QtSurface(m_activity, 0);
|
||||
m_editText = new QtEditText(m_activity);
|
||||
m_imm = (InputMethodManager)m_activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
m_layout.addView(m_surface,0);
|
||||
m_activity.setContentView(m_layout,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT));
|
||||
m_layout.bringChildToFront(m_surface);
|
||||
m_activity.registerForContextMenu(m_layout);
|
||||
|
||||
m_currentOrientation = m_activity.getResources().getConfiguration().orientation;
|
||||
}
|
||||
|
||||
public void onConfigurationChanged(Configuration configuration)
|
||||
{
|
||||
try {
|
||||
m_super_onConfigurationChanged.invoke(m_activity, configuration);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (configuration.orientation != m_currentOrientation
|
||||
&& m_currentOrientation != Configuration.ORIENTATION_UNDEFINED) {
|
||||
QtNative.handleOrientationChanged(configuration.orientation);
|
||||
}
|
||||
|
||||
m_currentOrientation = configuration.orientation;
|
||||
}
|
||||
|
||||
public void onDestroy()
|
||||
{
|
||||
if (m_quitApp) {
|
||||
if (m_debuggerProcess != null)
|
||||
m_debuggerProcess.destroy();
|
||||
System.exit(0);// FIXME remove it or find a better way
|
||||
}
|
||||
}
|
||||
|
||||
public void onRestoreInstanceState(Bundle savedInstanceState)
|
||||
{
|
||||
try {
|
||||
m_super_onRestoreInstanceState.invoke(m_activity, savedInstanceState);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// setFullScreen(savedInstanceState.getBoolean("FullScreen"));
|
||||
m_started = savedInstanceState.getBoolean("Started");
|
||||
if (m_started)
|
||||
m_surface.applicationStarted(true);
|
||||
}
|
||||
|
||||
public void onResume()
|
||||
{
|
||||
// fire all lostActions
|
||||
synchronized (QtNative.m_mainActivityMutex)
|
||||
{
|
||||
Iterator<Runnable> itr = QtNative.getLostActions().iterator();
|
||||
while (itr.hasNext())
|
||||
m_activity.runOnUiThread(itr.next());
|
||||
|
||||
if (m_started) {
|
||||
QtNative.clearLostActions();
|
||||
QtNative.updateWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object onRetainNonConfigurationInstance()
|
||||
{
|
||||
try {
|
||||
m_super_onRetainNonConfigurationInstance.invoke(m_activity);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
m_quitApp = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
try {
|
||||
m_super_onSaveInstanceState.invoke(m_activity, outState);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
outState.putBoolean("FullScreen", m_fullScreen);
|
||||
outState.putBoolean("Started", m_started);
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
if (!m_started)
|
||||
return false;
|
||||
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
try {
|
||||
return (Boolean)m_super_onKeyDown.invoke(m_activity, keyCode, event);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event);
|
||||
int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(m_metaState));
|
||||
int lc = c;
|
||||
m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState);
|
||||
|
||||
if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
|
||||
c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
|
||||
int composed = KeyEvent.getDeadChar(m_lastChar, c);
|
||||
c = composed;
|
||||
}
|
||||
|
||||
m_lastChar = lc;
|
||||
if (keyCode != KeyEvent.KEYCODE_BACK)
|
||||
QtNative.keyDown(keyCode, c, event.getMetaState());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
if (!m_started)
|
||||
return false;
|
||||
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
try {
|
||||
return (Boolean)m_super_onKeyUp.invoke(m_activity, keyCode, event);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && m_keyboardIsVisible)
|
||||
{
|
||||
if (!m_keyboardIsHiding)
|
||||
hideSoftwareKeyboard();
|
||||
return true;
|
||||
}
|
||||
|
||||
m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event);
|
||||
QtNative.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean dispatchKeyEvent(KeyEvent event)
|
||||
{
|
||||
if (m_started
|
||||
&& event.getAction() == KeyEvent.ACTION_MULTIPLE
|
||||
&& event.getCharacters() != null
|
||||
&& event.getCharacters().length() == 1
|
||||
&& event.getKeyCode() == 0) {
|
||||
QtNative.keyDown(0, event.getCharacters().charAt(0), event.getMetaState());
|
||||
QtNative.keyUp(0, event.getCharacters().charAt(0), event.getMetaState());
|
||||
}
|
||||
|
||||
try {
|
||||
return (Boolean) m_super_dispatchKeyEvent.invoke(m_activity, event);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean m_opionsMenuIsVisible = false;
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
menu.clear();
|
||||
return true;
|
||||
}
|
||||
public boolean onPrepareOptionsMenu(Menu menu)
|
||||
{
|
||||
m_opionsMenuIsVisible = true;
|
||||
return QtNative.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
return QtNative.onOptionsItemSelected(item.getItemId(), item.isChecked());
|
||||
}
|
||||
|
||||
public void onOptionsMenuClosed(Menu menu)
|
||||
{
|
||||
m_opionsMenuIsVisible = false;
|
||||
QtNative.onOptionsMenuClosed(menu);
|
||||
}
|
||||
|
||||
public void resetOptionsMenu()
|
||||
{
|
||||
if (m_opionsMenuIsVisible)
|
||||
m_activity.closeOptionsMenu();
|
||||
}
|
||||
private boolean m_contextMenuVisible = false;
|
||||
public void onCreateContextMenu(ContextMenu menu,
|
||||
View v,
|
||||
ContextMenuInfo menuInfo)
|
||||
{
|
||||
menu.clearHeader();
|
||||
QtNative.onCreateContextMenu(menu);
|
||||
m_contextMenuVisible = true;
|
||||
}
|
||||
|
||||
public void onContextMenuClosed(Menu menu)
|
||||
{
|
||||
if (!m_contextMenuVisible) {
|
||||
Log.e(QtNative.QtTAG, "invalid onContextMenuClosed call");
|
||||
return;
|
||||
}
|
||||
m_contextMenuVisible = false;
|
||||
QtNative.onContextMenuClosed(menu);
|
||||
}
|
||||
|
||||
public boolean onContextItemSelected(MenuItem item)
|
||||
{
|
||||
return QtNative.onContextItemSelected(item.getItemId(), item.isChecked());
|
||||
}
|
||||
|
||||
public void openContextMenu()
|
||||
{
|
||||
m_layout.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activity.openContextMenu(m_layout);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
public void closeContextMenu()
|
||||
{
|
||||
m_activity.closeContextMenu();
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
package org.qtproject.qt5.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.InputType;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
public class QtEditText extends View
|
||||
{
|
||||
QtInputConnection m_inputConnection;
|
||||
int m_initialCapsMode = 0;
|
||||
int m_imeOptions = 0;
|
||||
int m_inputType = InputType.TYPE_CLASS_TEXT;
|
||||
|
||||
public void setImeOptions(int m_imeOptions)
|
||||
{
|
||||
this.m_imeOptions = m_imeOptions;
|
||||
}
|
||||
|
||||
public void setInitialCapsMode(int m_initialCapsMode)
|
||||
{
|
||||
this.m_initialCapsMode = m_initialCapsMode;
|
||||
}
|
||||
|
||||
|
||||
public void setInputType(int m_inputType)
|
||||
{
|
||||
this.m_inputType = m_inputType;
|
||||
}
|
||||
|
||||
public QtEditText(Context context)
|
||||
{
|
||||
super(context);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
m_inputConnection = new QtInputConnection(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs)
|
||||
{
|
||||
outAttrs.inputType = m_inputType;
|
||||
outAttrs.imeOptions = m_imeOptions;
|
||||
outAttrs.initialCapsMode = m_initialCapsMode;
|
||||
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
|
||||
return m_inputConnection;
|
||||
}
|
||||
// // DEBUG CODE
|
||||
// @Override
|
||||
// protected void onDraw(Canvas canvas) {
|
||||
// canvas.drawARGB(127, 255, 0, 255);
|
||||
// super.onDraw(canvas);
|
||||
// }
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
package org.qtproject.qt5.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.view.inputmethod.CompletionInfo;
|
||||
import android.view.inputmethod.ExtractedText;
|
||||
import android.view.inputmethod.ExtractedTextRequest;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
class QtExtractedText
|
||||
{
|
||||
public int partialEndOffset;
|
||||
public int partialStartOffset;
|
||||
public int selectionEnd;
|
||||
public int selectionStart;
|
||||
public int startOffset;
|
||||
public String text;
|
||||
}
|
||||
|
||||
class QtNativeInputConnection
|
||||
{
|
||||
static native boolean commitText(String text, int newCursorPosition);
|
||||
static native boolean commitCompletion(String text, int position);
|
||||
static native boolean deleteSurroundingText(int leftLength, int rightLength);
|
||||
static native boolean finishComposingText();
|
||||
static native int getCursorCapsMode(int reqModes);
|
||||
static native QtExtractedText getExtractedText(int hintMaxChars, int hintMaxLines, int flags);
|
||||
static native String getSelectedText(int flags);
|
||||
static native String getTextAfterCursor(int length, int flags);
|
||||
static native String getTextBeforeCursor(int length, int flags);
|
||||
static native boolean setComposingText(String text, int newCursorPosition);
|
||||
static native boolean setSelection(int start, int end);
|
||||
static native boolean selectAll();
|
||||
static native boolean cut();
|
||||
static native boolean copy();
|
||||
static native boolean copyURL();
|
||||
static native boolean paste();
|
||||
}
|
||||
|
||||
public class QtInputConnection extends BaseInputConnection
|
||||
{
|
||||
private static final int ID_SELECT_ALL = android.R.id.selectAll;
|
||||
private static final int ID_CUT = android.R.id.cut;
|
||||
private static final int ID_COPY = android.R.id.copy;
|
||||
private static final int ID_PASTE = android.R.id.paste;
|
||||
private static final int ID_COPY_URL = android.R.id.copyUrl;
|
||||
private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
|
||||
private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
|
||||
|
||||
View m_view;
|
||||
boolean m_closing;
|
||||
public QtInputConnection(View targetView)
|
||||
{
|
||||
super(targetView, true);
|
||||
m_view = targetView;
|
||||
m_closing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beginBatchEdit()
|
||||
{
|
||||
m_closing = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean endBatchEdit()
|
||||
{
|
||||
m_closing = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitCompletion(CompletionInfo text)
|
||||
{
|
||||
m_closing = false;
|
||||
return QtNativeInputConnection.commitCompletion(text.getText().toString(), text.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition)
|
||||
{
|
||||
m_closing = false;
|
||||
return QtNativeInputConnection.commitText(text.toString(), newCursorPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int leftLength, int rightLength)
|
||||
{
|
||||
m_closing = false;
|
||||
return QtNativeInputConnection.deleteSurroundingText(leftLength, rightLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finishComposingText()
|
||||
{
|
||||
if (m_closing) {
|
||||
QtNative.activityDelegate().m_keyboardIsHiding = true;
|
||||
m_view.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (QtNative.activityDelegate().m_keyboardIsHiding)
|
||||
QtNative.activityDelegate().m_keyboardIsVisible=false;
|
||||
}
|
||||
}, 5000); // it seems finishComposingText comes musch faster than onKeyUp event,
|
||||
// so we must delay hide notification
|
||||
m_closing = false;
|
||||
} else {
|
||||
m_closing = true;
|
||||
}
|
||||
return QtNativeInputConnection.finishComposingText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCursorCapsMode(int reqModes)
|
||||
{
|
||||
return QtNativeInputConnection.getCursorCapsMode(reqModes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags)
|
||||
{
|
||||
QtExtractedText qExtractedText = QtNativeInputConnection.getExtractedText(request.hintMaxChars,
|
||||
request.hintMaxLines,
|
||||
flags);
|
||||
ExtractedText extractedText = new ExtractedText();
|
||||
extractedText.partialEndOffset = qExtractedText.partialEndOffset;
|
||||
extractedText.partialStartOffset = qExtractedText.partialStartOffset;
|
||||
extractedText.selectionEnd = qExtractedText.selectionEnd;
|
||||
extractedText.selectionStart = qExtractedText.selectionStart;
|
||||
extractedText.startOffset = qExtractedText.startOffset;
|
||||
extractedText.text = qExtractedText.text;
|
||||
return extractedText;
|
||||
}
|
||||
|
||||
public CharSequence getSelectedText(int flags)
|
||||
{
|
||||
return QtNativeInputConnection.getSelectedText(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTextAfterCursor(int length, int flags)
|
||||
{
|
||||
return QtNativeInputConnection.getTextAfterCursor(length, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTextBeforeCursor(int length, int flags)
|
||||
{
|
||||
return QtNativeInputConnection.getTextBeforeCursor(length, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performContextMenuAction(int id)
|
||||
{
|
||||
switch (id) {
|
||||
case ID_SELECT_ALL:
|
||||
return QtNativeInputConnection.selectAll();
|
||||
case ID_COPY:
|
||||
return QtNativeInputConnection.copy();
|
||||
case ID_COPY_URL:
|
||||
return QtNativeInputConnection.copyURL();
|
||||
case ID_CUT:
|
||||
return QtNativeInputConnection.cut();
|
||||
case ID_PASTE:
|
||||
return QtNativeInputConnection.paste();
|
||||
|
||||
case ID_SWITCH_INPUT_METHOD:
|
||||
InputMethodManager imm = (InputMethodManager)m_view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null)
|
||||
imm.showInputMethodPicker();
|
||||
|
||||
return true;
|
||||
|
||||
case ID_ADD_TO_DICTIONARY:
|
||||
// TODO
|
||||
// String word = m_editable.subSequence(0, m_editable.length()).toString();
|
||||
// if (word != null) {
|
||||
// Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
|
||||
// i.putExtra("word", word);
|
||||
// i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// m_view.getContext().startActivity(i);
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
return super.performContextMenuAction(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition)
|
||||
{
|
||||
return QtNativeInputConnection.setComposingText(text.toString(), newCursorPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSelection(int start, int end)
|
||||
{
|
||||
return QtNativeInputConnection.setSelection(start, end);
|
||||
}
|
||||
}
|
201
src/android/jar/src/org/qtproject/qt5/android/QtLayout.java
Normal file
201
src/android/jar/src/org/qtproject/qt5/android/QtLayout.java
Normal file
@ -0,0 +1,201 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
package org.qtproject.qt5.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class QtLayout extends ViewGroup
|
||||
{
|
||||
public QtLayout(Context context)
|
||||
{
|
||||
super(context);
|
||||
}
|
||||
|
||||
public QtLayout(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public QtLayout(Context context, AttributeSet attrs, int defStyle)
|
||||
{
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
int count = getChildCount();
|
||||
|
||||
int maxHeight = 0;
|
||||
int maxWidth = 0;
|
||||
|
||||
// Find out how big everyone wants to be
|
||||
measureChildren(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
// Find rightmost and bottom-most child
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
if (child.getVisibility() != GONE) {
|
||||
int childRight;
|
||||
int childBottom;
|
||||
|
||||
QtLayout.LayoutParams lp
|
||||
= (QtLayout.LayoutParams) child.getLayoutParams();
|
||||
|
||||
childRight = lp.x + child.getMeasuredWidth();
|
||||
childBottom = lp.y + child.getMeasuredHeight();
|
||||
|
||||
maxWidth = Math.max(maxWidth, childRight);
|
||||
maxHeight = Math.max(maxHeight, childBottom);
|
||||
}
|
||||
}
|
||||
|
||||
// Check against minimum height and width
|
||||
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
|
||||
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
|
||||
|
||||
setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
|
||||
resolveSize(maxHeight, heightMeasureSpec));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of layout parameters with a width of
|
||||
* {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT},
|
||||
* a height of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
|
||||
* and with the coordinates (0, 0).
|
||||
*/
|
||||
@Override
|
||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams()
|
||||
{
|
||||
return new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b)
|
||||
{
|
||||
int count = getChildCount();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
if (child.getVisibility() != GONE) {
|
||||
QtLayout.LayoutParams lp =
|
||||
(QtLayout.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int childLeft = lp.x;
|
||||
int childTop = lp.y;
|
||||
child.layout(childLeft, childTop,
|
||||
childLeft + child.getMeasuredWidth(),
|
||||
childTop + child.getMeasuredHeight());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override to allow type-checking of LayoutParams.
|
||||
@Override
|
||||
protected boolean checkLayoutParams(ViewGroup.LayoutParams p)
|
||||
{
|
||||
return p instanceof QtLayout.LayoutParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p)
|
||||
{
|
||||
return new LayoutParams(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-child layout information associated with AbsoluteLayout.
|
||||
* See
|
||||
* {@link android.R.styleable#AbsoluteLayout_Layout Absolute Layout Attributes}
|
||||
* for a list of all child view attributes that this class supports.
|
||||
*/
|
||||
public static class LayoutParams extends ViewGroup.LayoutParams
|
||||
{
|
||||
/**
|
||||
* The horizontal, or X, location of the child within the view group.
|
||||
*/
|
||||
public int x;
|
||||
/**
|
||||
* The vertical, or Y, location of the child within the view group.
|
||||
*/
|
||||
public int y;
|
||||
|
||||
/**
|
||||
* Creates a new set of layout parameters with the specified width,
|
||||
* height and location.
|
||||
*
|
||||
* @param width the width, either {@link #FILL_PARENT},
|
||||
{@link #WRAP_CONTENT} or a fixed size in pixels
|
||||
* @param height the height, either {@link #FILL_PARENT},
|
||||
{@link #WRAP_CONTENT} or a fixed size in pixels
|
||||
* @param x the X location of the child
|
||||
* @param y the Y location of the child
|
||||
*/
|
||||
public LayoutParams(int width, int height, int x, int y)
|
||||
{
|
||||
super(width, height);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public LayoutParams(ViewGroup.LayoutParams source)
|
||||
{
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
public void bringChildFront(int child)
|
||||
{
|
||||
bringChildToFront(getChildAt(child));
|
||||
}
|
||||
}
|
611
src/android/jar/src/org/qtproject/qt5/android/QtNative.java
Normal file
611
src/android/jar/src/org/qtproject/qt5/android/QtNative.java
Normal file
@ -0,0 +1,611 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
package org.qtproject.qt5.android;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.ClipboardManager;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class QtNative
|
||||
{
|
||||
private static Activity m_activity = null;
|
||||
private static QtActivityDelegate m_activityDelegate = 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
|
||||
private static ArrayList<Runnable> m_lostActions = new ArrayList<Runnable>(); // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.)
|
||||
private static boolean m_started = false;
|
||||
private static int m_displayMetricsScreenWidthPixels = 0;
|
||||
private static int m_displayMetricsScreenHeightPixels = 0;
|
||||
private static int m_displayMetricsDesktopWidthPixels = 0;
|
||||
private static int m_displayMetricsDesktopHeightPixels = 0;
|
||||
private static double m_displayMetricsXDpi = .0;
|
||||
private static double m_displayMetricsYDpi = .0;
|
||||
private static int m_oldx, m_oldy;
|
||||
private static final int m_moveThreshold = 0;
|
||||
private static ClipboardManager m_clipboardManager = null;
|
||||
|
||||
private static ClassLoader m_classLoader = null;
|
||||
public static ClassLoader classLoader()
|
||||
{
|
||||
return m_classLoader;
|
||||
}
|
||||
|
||||
public static void setClassLoader(ClassLoader classLoader)
|
||||
{
|
||||
m_classLoader = classLoader;
|
||||
}
|
||||
|
||||
public static Activity activity()
|
||||
{
|
||||
synchronized (m_mainActivityMutex) {
|
||||
return m_activity;
|
||||
}
|
||||
}
|
||||
|
||||
public static QtActivityDelegate activityDelegate()
|
||||
{
|
||||
synchronized (m_mainActivityMutex) {
|
||||
return m_activityDelegate;
|
||||
}
|
||||
}
|
||||
|
||||
public static void openURL(String url)
|
||||
{
|
||||
Uri uri = Uri.parse(url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
activity().startActivity(intent);
|
||||
}
|
||||
|
||||
// this method loads full path libs
|
||||
public static void loadQtLibraries(ArrayList<String> libraries)
|
||||
{
|
||||
if (libraries == null)
|
||||
return;
|
||||
|
||||
for (String libName : libraries) {
|
||||
try {
|
||||
File f = new File(libName);
|
||||
if (f.exists())
|
||||
System.load(libName);
|
||||
} catch (SecurityException e) {
|
||||
Log.i(QtTAG, "Can't load '" + libName + "'", e);
|
||||
} catch (Exception e) {
|
||||
Log.i(QtTAG, "Can't load '" + libName + "'", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this method loads bundled libs by name.
|
||||
public static void loadBundledLibraries(ArrayList<String> libraries, String nativeLibraryDir)
|
||||
{
|
||||
if (libraries == null)
|
||||
return;
|
||||
|
||||
for (String libName : libraries) {
|
||||
try {
|
||||
File f = new File(nativeLibraryDir+"lib"+libName+".so");
|
||||
if (f.exists())
|
||||
System.load(f.getAbsolutePath());
|
||||
else
|
||||
Log.i(QtTAG, "Can't find '" + f.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
Log.i(QtTAG, "Can't load '" + libName + "'", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setActivity(Activity qtMainActivity, QtActivityDelegate qtActivityDelegate)
|
||||
{
|
||||
synchronized (m_mainActivityMutex) {
|
||||
m_activity = qtMainActivity;
|
||||
m_activityDelegate = qtActivityDelegate;
|
||||
}
|
||||
}
|
||||
|
||||
static public ArrayList<Runnable> getLostActions()
|
||||
{
|
||||
return m_lostActions;
|
||||
}
|
||||
|
||||
static public void clearLostActions()
|
||||
{
|
||||
m_lostActions.clear();
|
||||
}
|
||||
|
||||
private static boolean runAction(Runnable action)
|
||||
{
|
||||
synchronized (m_mainActivityMutex) {
|
||||
if (m_activity == null)
|
||||
m_lostActions.add(action);
|
||||
else
|
||||
m_activity.runOnUiThread(action);
|
||||
return m_activity != null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean startApplication(String params,
|
||||
String environment,
|
||||
String mainLibrary,
|
||||
String nativeLibraryDir) throws Exception
|
||||
{
|
||||
File f = new File(nativeLibraryDir + "lib" + mainLibrary + ".so");
|
||||
if (!f.exists())
|
||||
throw new Exception("Can't find main library '" + mainLibrary + "'");
|
||||
|
||||
if (params == null)
|
||||
params = "-platform\tandroid";
|
||||
|
||||
boolean res = false;
|
||||
synchronized (m_mainActivityMutex) {
|
||||
res = startQtAndroidPlugin();
|
||||
setDisplayMetrics(m_displayMetricsScreenWidthPixels,
|
||||
m_displayMetricsScreenHeightPixels,
|
||||
m_displayMetricsDesktopWidthPixels,
|
||||
m_displayMetricsDesktopHeightPixels,
|
||||
m_displayMetricsXDpi,
|
||||
m_displayMetricsYDpi);
|
||||
if (params.length() > 0)
|
||||
params = "\t" + params;
|
||||
startQtApplication(f.getAbsolutePath() + "\t" + params, environment);
|
||||
m_started = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void setApplicationDisplayMetrics(int screenWidthPixels,
|
||||
int screenHeightPixels,
|
||||
int desktopWidthPixels,
|
||||
int desktopHeightPixels,
|
||||
double XDpi,
|
||||
double YDpi)
|
||||
{
|
||||
/* Fix buggy dpi report */
|
||||
if (XDpi < android.util.DisplayMetrics.DENSITY_LOW)
|
||||
XDpi = android.util.DisplayMetrics.DENSITY_LOW;
|
||||
if (YDpi < android.util.DisplayMetrics.DENSITY_LOW)
|
||||
YDpi = android.util.DisplayMetrics.DENSITY_LOW;
|
||||
|
||||
synchronized (m_mainActivityMutex) {
|
||||
if (m_started) {
|
||||
setDisplayMetrics(screenWidthPixels,
|
||||
screenHeightPixels,
|
||||
desktopWidthPixels,
|
||||
desktopHeightPixels,
|
||||
XDpi,
|
||||
YDpi);
|
||||
} else {
|
||||
m_displayMetricsScreenWidthPixels = screenWidthPixels;
|
||||
m_displayMetricsScreenHeightPixels = screenHeightPixels;
|
||||
m_displayMetricsDesktopWidthPixels = desktopWidthPixels;
|
||||
m_displayMetricsDesktopHeightPixels = desktopHeightPixels;
|
||||
m_displayMetricsXDpi = XDpi;
|
||||
m_displayMetricsYDpi = YDpi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void pauseApplication()
|
||||
{
|
||||
synchronized (m_mainActivityMutex) {
|
||||
if (m_started)
|
||||
pauseQtApp();
|
||||
}
|
||||
}
|
||||
|
||||
public static void resumeApplication()
|
||||
{
|
||||
synchronized (m_mainActivityMutex) {
|
||||
if (m_started) {
|
||||
resumeQtApp();
|
||||
updateWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// application methods
|
||||
public static native void startQtApplication(String params, String env);
|
||||
public static native void startQtApp(String params, String env);
|
||||
public static native void pauseQtApp();
|
||||
public static native void resumeQtApp();
|
||||
public static native boolean startQtAndroidPlugin();
|
||||
public static native void quitQtAndroidPlugin();
|
||||
public static native void terminateQt();
|
||||
// application methods
|
||||
|
||||
private static void quitApp()
|
||||
{
|
||||
m_activity.finish();
|
||||
}
|
||||
|
||||
private static void redrawSurface(final int left, final int top, final int right, final int bottom )
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.redrawWindow(left, top, right, bottom);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//@ANDROID-5
|
||||
static private int getAction(int index, MotionEvent event)
|
||||
{
|
||||
int action = event.getAction();
|
||||
if (action == MotionEvent.ACTION_MOVE) {
|
||||
int hsz = event.getHistorySize();
|
||||
if (hsz > 0) {
|
||||
if (Math.abs(event.getX(index) - event.getHistoricalX(index, hsz-1)) > 1
|
||||
|| Math.abs(event.getY(index) - event.getHistoricalY(index, hsz-1)) > 1) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
if (action == MotionEvent.ACTION_DOWN
|
||||
|| action == MotionEvent.ACTION_POINTER_1_DOWN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (action == MotionEvent.ACTION_UP
|
||||
|| action == MotionEvent.ACTION_POINTER_1_UP) {
|
||||
return 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (action == MotionEvent.ACTION_POINTER_2_DOWN
|
||||
|| action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (action == MotionEvent.ACTION_POINTER_2_UP
|
||||
|| action == MotionEvent.ACTION_POINTER_UP) {
|
||||
return 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (action == MotionEvent.ACTION_POINTER_3_DOWN
|
||||
|| action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (action == MotionEvent.ACTION_POINTER_3_UP
|
||||
|| action == MotionEvent.ACTION_POINTER_UP) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
//@ANDROID-5
|
||||
|
||||
static public void sendTouchEvent(MotionEvent event, int id)
|
||||
{
|
||||
//@ANDROID-5
|
||||
touchBegin(id);
|
||||
for (int i=0;i<event.getPointerCount();i++) {
|
||||
touchAdd(id,
|
||||
event.getPointerId(i),
|
||||
getAction(i, event),
|
||||
i == 0,
|
||||
(int)event.getX(i),
|
||||
(int)event.getY(i),
|
||||
event.getSize(i),
|
||||
event.getPressure(i));
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
touchEnd(id,0);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
touchEnd(id,2);
|
||||
break;
|
||||
|
||||
default:
|
||||
touchEnd(id,1);
|
||||
}
|
||||
//@ANDROID-5
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
mouseUp(id,(int) event.getX(), (int) event.getY());
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mouseDown(id,(int) event.getX(), (int) event.getY());
|
||||
m_oldx = (int) event.getX();
|
||||
m_oldy = (int) event.getY();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int dx = (int) (event.getX() - m_oldx);
|
||||
int dy = (int) (event.getY() - m_oldy);
|
||||
if (Math.abs(dx) > m_moveThreshold || Math.abs(dy) > m_moveThreshold) {
|
||||
mouseMove(id, (int) event.getX(), (int) event.getY());
|
||||
m_oldx = (int) event.getX();
|
||||
m_oldy = (int) event.getY();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static public void sendTrackballEvent(MotionEvent event, int id)
|
||||
{
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
mouseUp(id, (int) event.getX(), (int) event.getY());
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mouseDown(id, (int) event.getX(), (int) event.getY());
|
||||
m_oldx = (int) event.getX();
|
||||
m_oldy = (int) event.getY();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int dx = (int) (event.getX() - m_oldx);
|
||||
int dy = (int) (event.getY() - m_oldy);
|
||||
if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
|
||||
mouseMove(id, (int) event.getX(), (int) event.getY());
|
||||
m_oldx = (int) event.getX();
|
||||
m_oldy = (int) event.getY();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateSelection(final int selStart,
|
||||
final int selEnd,
|
||||
final int candidatesStart,
|
||||
final int candidatesEnd)
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.updateSelection(selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void showSoftwareKeyboard(final int x,
|
||||
final int y,
|
||||
final int width,
|
||||
final int height,
|
||||
final int inputHints )
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void resetSoftwareKeyboard()
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.resetSoftwareKeyboard();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void hideSoftwareKeyboard()
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.hideSoftwareKeyboard();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isSoftwareKeyboardVisible()
|
||||
{
|
||||
Semaphore semaphore = new Semaphore(1);
|
||||
Boolean ret = false;
|
||||
class RunnableRes implements Runnable {
|
||||
@SuppressWarnings("unused")
|
||||
Boolean returnValue = null;
|
||||
Semaphore semaphore = null;
|
||||
RunnableRes(Boolean ret, Semaphore sem) {
|
||||
semaphore = sem;
|
||||
returnValue = ret;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
returnValue = m_activityDelegate.isSoftwareKeyboardVisible();
|
||||
semaphore.release();
|
||||
}
|
||||
}
|
||||
|
||||
runAction(new RunnableRes(ret, semaphore));
|
||||
try {
|
||||
semaphore.acquire();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void setFullScreen(final boolean fullScreen)
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.setFullScreen(fullScreen);
|
||||
updateWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerClipboardManager()
|
||||
{
|
||||
final Semaphore semaphore = new Semaphore(1);
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_clipboardManager = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
try {
|
||||
semaphore.acquire();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void setClipboardText(String text)
|
||||
{
|
||||
m_clipboardManager.setText(text);
|
||||
}
|
||||
|
||||
private static boolean hasClipboardText()
|
||||
{
|
||||
return m_clipboardManager.hasText();
|
||||
}
|
||||
|
||||
private static String getClipboardText()
|
||||
{
|
||||
return m_clipboardManager.getText().toString();
|
||||
}
|
||||
|
||||
private static void openContextMenu()
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.openContextMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void closeContextMenu()
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.closeContextMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void resetOptionsMenu()
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.resetOptionsMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// screen methods
|
||||
public static native void setDisplayMetrics(int screenWidthPixels,
|
||||
int screenHeightPixels,
|
||||
int desktopWidthPixels,
|
||||
int desktopHeightPixels,
|
||||
double XDpi,
|
||||
double YDpi);
|
||||
public static native void handleOrientationChanged(int newOrientation);
|
||||
// screen methods
|
||||
|
||||
// pointer methods
|
||||
public static native void mouseDown(int winId, int x, int y);
|
||||
public static native void mouseUp(int winId, int x, int y);
|
||||
public static native void mouseMove(int winId, int x, int y);
|
||||
public static native void touchBegin(int winId);
|
||||
public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float size, float pressure);
|
||||
public static native void touchEnd(int winId, int action);
|
||||
public static native void longPress(int winId, int x, int y);
|
||||
// pointer methods
|
||||
|
||||
// keyboard methods
|
||||
public static native void keyDown(int key, int unicode, int modifier);
|
||||
public static native void keyUp(int key, int unicode, int modifier);
|
||||
// keyboard methods
|
||||
|
||||
// surface methods
|
||||
public static native void destroySurface();
|
||||
public static native void setSurface(Object surface);
|
||||
public static native void lockSurface();
|
||||
public static native void unlockSurface();
|
||||
// surface methods
|
||||
|
||||
// window methods
|
||||
public static native void updateWindow();
|
||||
// window methods
|
||||
|
||||
// menu methods
|
||||
public static native boolean onPrepareOptionsMenu(Menu menu);
|
||||
public static native boolean onOptionsItemSelected(int itemId, boolean checked);
|
||||
public static native void onOptionsMenuClosed(Menu menu);
|
||||
|
||||
public static native void onCreateContextMenu(ContextMenu menu);
|
||||
public static native boolean onContextItemSelected(int itemId, boolean checked);
|
||||
public static native void onContextMenuClosed(Menu menu);
|
||||
// menu methods
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
package org.qtproject.qt5.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
|
||||
public class QtNativeLibrariesDir {
|
||||
public static String nativeLibrariesDir(Activity activity)
|
||||
{
|
||||
String m_nativeLibraryDir = null;
|
||||
try {
|
||||
ApplicationInfo ai = activity.getPackageManager().getApplicationInfo(activity.getPackageName(), 0);
|
||||
m_nativeLibraryDir = ai.nativeLibraryDir+"/";
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return m_nativeLibraryDir;
|
||||
}
|
||||
}
|
206
src/android/jar/src/org/qtproject/qt5/android/QtSurface.java
Normal file
206
src/android/jar/src/org/qtproject/qt5/android/QtSurface.java
Normal file
@ -0,0 +1,206 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
package org.qtproject.qt5.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
public class QtSurface extends SurfaceView implements SurfaceHolder.Callback
|
||||
{
|
||||
private Bitmap m_bitmap = null;
|
||||
private boolean m_started = false;
|
||||
private boolean m_usesGL = false;
|
||||
private GestureDetector m_gestureDetector;
|
||||
|
||||
public QtSurface(Context context, int id)
|
||||
{
|
||||
super(context);
|
||||
setFocusable(true);
|
||||
getHolder().addCallback(this);
|
||||
getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||
setId(id);
|
||||
m_gestureDetector =
|
||||
new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||
public void onLongPress(MotionEvent event) {
|
||||
if (!m_started)
|
||||
return;
|
||||
QtNative.longPress(getId(), (int) event.getX(), (int) event.getY());
|
||||
}
|
||||
});
|
||||
m_gestureDetector.setIsLongpressEnabled(true);
|
||||
}
|
||||
|
||||
public void applicationStarted(boolean usesGL)
|
||||
{
|
||||
m_started = true;
|
||||
m_usesGL = usesGL;
|
||||
if (getWidth() < 1 || getHeight() < 1)
|
||||
return;
|
||||
if (m_usesGL) {
|
||||
QtNative.setSurface(getHolder().getSurface());
|
||||
} else {
|
||||
QtNative.lockSurface();
|
||||
QtNative.setSurface(null);
|
||||
m_bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
|
||||
QtNative.setSurface(m_bitmap);
|
||||
QtNative.unlockSurface();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder)
|
||||
{
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
QtNative.setApplicationDisplayMetrics(metrics.widthPixels,
|
||||
metrics.heightPixels, getWidth(), getHeight(), metrics.xdpi, metrics.ydpi);
|
||||
|
||||
if (m_usesGL)
|
||||
holder.setFormat(PixelFormat.RGBA_8888);
|
||||
|
||||
// if (!m_started)
|
||||
// return;
|
||||
//
|
||||
// if (m_usesGL)
|
||||
// QtApplication.setSurface(holder.getSurface());
|
||||
// else
|
||||
// {
|
||||
// QtApplication.lockSurface();
|
||||
// QtApplication.setSurface(null);
|
||||
// m_bitmap=Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
|
||||
// QtApplication.setSurface(m_bitmap);
|
||||
// QtApplication.unlockSurface();
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||
{
|
||||
if (width<1 || height<1)
|
||||
return;
|
||||
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
QtNative.setApplicationDisplayMetrics(metrics.widthPixels,
|
||||
metrics.heightPixels,
|
||||
width,
|
||||
height,
|
||||
metrics.xdpi,
|
||||
metrics.ydpi);
|
||||
|
||||
if (!m_started)
|
||||
return;
|
||||
|
||||
if (m_usesGL) {
|
||||
QtNative.setSurface(holder.getSurface());
|
||||
} else {
|
||||
QtNative.lockSurface();
|
||||
QtNative.setSurface(null);
|
||||
m_bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
||||
QtNative.setSurface(m_bitmap);
|
||||
QtNative.unlockSurface();
|
||||
QtNative.updateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
if (m_usesGL) {
|
||||
QtNative.destroySurface();
|
||||
} else {
|
||||
if (!m_started)
|
||||
return;
|
||||
|
||||
QtNative.lockSurface();
|
||||
QtNative.setSurface(null);
|
||||
QtNative.unlockSurface();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawBitmap(Rect rect)
|
||||
{
|
||||
if (!m_started)
|
||||
return;
|
||||
QtNative.lockSurface();
|
||||
if (null != m_bitmap) {
|
||||
try {
|
||||
Canvas cv = getHolder().lockCanvas(rect);
|
||||
cv.drawBitmap(m_bitmap, rect, rect, null);
|
||||
getHolder().unlockCanvasAndPost(cv);
|
||||
} catch (Exception e) {
|
||||
Log.e(QtNative.QtTAG, "Can't create main activity", e);
|
||||
}
|
||||
}
|
||||
QtNative.unlockSurface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event)
|
||||
{
|
||||
if (!m_started)
|
||||
return false;
|
||||
QtNative.sendTouchEvent(event, getId());
|
||||
m_gestureDetector.onTouchEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrackballEvent(MotionEvent event)
|
||||
{
|
||||
if (!m_started)
|
||||
return false;
|
||||
QtNative.sendTrackballEvent(event, getId());
|
||||
return true;
|
||||
}
|
||||
}
|
25
src/android/java/AndroidManifest.xml
Normal file
25
src/android/java/AndroidManifest.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="org.kde.necessitas.example">
|
||||
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="@string/app_name">
|
||||
<activity android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="@string/app_name" android:configChanges="orientation|locale|fontScale|keyboard|keyboardHidden" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<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"/>
|
||||
<meta-data android:name="android.app.lib_name" android:value=""/>
|
||||
<!-- Messages maps -->
|
||||
<meta-data android:name="android.app.ministro_not_found_msg" android:value="@string/ministro_not_found_msg"/>
|
||||
<meta-data android:name="android.app.ministro_needed_msg" android:value="@string/ministro_needed_msg"/>
|
||||
<meta-data android:name="android.app.fatal_error_msg" android:value="@string/fatal_error_msg"/>
|
||||
<!-- Messages maps -->
|
||||
<!-- Splash screen -->
|
||||
<meta-data android:name="android.app.splash_screen" android:resource="@layout/splash"/>
|
||||
<!-- Splash screen -->
|
||||
</activity>
|
||||
</application>
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
</manifest>
|
13
src/android/java/res/layout/splash.xml
Normal file
13
src/android/java/res/layout/splash.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:scaleType="fitXY"
|
||||
/>
|
||||
</LinearLayout>
|
6
src/android/java/res/values-de/strings.xml
Normal file
6
src/android/java/res/values-de/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Ministro-Dienst wurde nicht gefunden.\nAnwendung kann nicht gestartet werden</string>
|
||||
<string name="ministro_needed_msg">Diese Anwendung benötigt den Ministro-Dienst. Möchten Sie ihn installieren?</string>
|
||||
<string name="fatal_error_msg">In Ihrer Anwendung ist ein schwerwiegender Fehler aufgetreten, sie kann nicht fortgesetzt werden</string>
|
||||
</resources>
|
6
src/android/java/res/values-el/strings.xml
Normal file
6
src/android/java/res/values-el/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Δεν ήταν δυνατή η εύρεση της υπηρεσίας Ministro. Δεν είναι δυνατή η εκκίνηση της εφαρμογής.</string>
|
||||
<string name="ministro_needed_msg">Η εφαρμογή απαιτεί την υπηρεσία Ministro. Να εγκατασταθεί η υπηρεσία?</string>
|
||||
<string name="fatal_error_msg">Παρουσιάστηκε ένα κρίσιμο σφάλμα και η εφαρμογή δεν μπορεί να συνεχίσει.</string>
|
||||
</resources>
|
6
src/android/java/res/values-es/strings.xml
Normal file
6
src/android/java/res/values-es/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Servicio Ministro inesistente. Imposible ejecutar la aplicación.</string>
|
||||
<string name="ministro_needed_msg">Esta aplicación requiere el servicio Ministro. Instalarlo?</string>
|
||||
<string name="fatal_error_msg">La aplicación ha causado un error grave y no es posible continuar.</string>
|
||||
</resources>
|
6
src/android/java/res/values-et/strings.xml
Normal file
6
src/android/java/res/values-et/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Ei suuda leida Ministro teenust.\nProgrammi ei saa käivitada.</string>
|
||||
<string name="ministro_needed_msg">See programm vajab Ministro teenust.\nKas soovite paigaldada?</string>
|
||||
<string name="fatal_error_msg">Programmiga juhtus fataalne viga.\nKahjuks ei saa jätkata.</string>
|
||||
</resources>
|
6
src/android/java/res/values-fa/strings.xml
Normal file
6
src/android/java/res/values-fa/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">سرویس Ministro را پیدا نمیکند. برنامه نمیتواند آغاز شود.</string>
|
||||
<string name="ministro_needed_msg">این نرمافزار به سرویس Ministro احتیاج دارد. آیا دوست دارید آن را نصب کنید؟</string>
|
||||
<string name="fatal_error_msg">خطایی اساسی در برنامهتان رخ داد و اجرای برنامه نمیتواند ادامه یابد.</string>
|
||||
</resources>
|
6
src/android/java/res/values-fr/strings.xml
Normal file
6
src/android/java/res/values-fr/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Le service Ministro est introuvable.\nL\'application ne peut pas démarrer.</string>
|
||||
<string name="ministro_needed_msg">Cette application requiert le service Ministro. Voulez-vous l\'installer?</string>
|
||||
<string name="fatal_error_msg">Votre application a rencontré une erreur fatale et ne peut pas continuer.</string>
|
||||
</resources>
|
6
src/android/java/res/values-id/strings.xml
Normal file
6
src/android/java/res/values-id/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Layanan Ministro tidak bisa ditemukan.\nAplikasi tidak bisa dimulai.</string>
|
||||
<string name="ministro_needed_msg">Aplikasi ini membutuhkan layanan Ministro. Apakah Anda ingin menginstalnya?</string>
|
||||
<string name="fatal_error_msg">Aplikasi Anda mengalami kesalahan fatal dan tidak dapat melanjutkan.</string>
|
||||
</resources>
|
6
src/android/java/res/values-it/strings.xml
Normal file
6
src/android/java/res/values-it/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Servizio Ministro inesistente. Impossibile eseguire \nl\'applicazione.</string>
|
||||
<string name="ministro_needed_msg">Questa applicazione richiede il servizio Ministro.Installarlo?</string>
|
||||
<string name="fatal_error_msg">L\'applicazione ha provocato un errore grave e non puo\' continuare.</string>
|
||||
</resources>
|
6
src/android/java/res/values-ja/strings.xml
Normal file
6
src/android/java/res/values-ja/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Ministroサービスが見つかりません。\nアプリケーションが起動できません。</string>
|
||||
<string name="ministro_needed_msg">このアプリケーションにはMinistroサービスが必要です。 インストールしてもよろしいですか?</string>
|
||||
<string name="fatal_error_msg">アプリケーションで致命的なエラーが発生したため続行できません。</string>
|
||||
</resources>
|
6
src/android/java/res/values-ms/strings.xml
Normal file
6
src/android/java/res/values-ms/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Tidak jumpa servis Ministro.\nAplikasi tidak boleh dimulakan.</string>
|
||||
<string name="ministro_needed_msg">Aplikasi ini memerlukan servis Ministro. Adakah anda ingin pasang servis itu?</string>
|
||||
<string name="fatal_error_msg">Aplikasi anda menemui ralat muat dan tidak boleh diteruskan.</string>
|
||||
</resources>
|
6
src/android/java/res/values-nb/strings.xml
Normal file
6
src/android/java/res/values-nb/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Kan ikke finne tjenesten Ministro. Applikasjonen kan ikke starte.</string>
|
||||
<string name="ministro_needed_msg">Denne applikasjonen krever tjenesten Ministro. Vil du installere denne?</string>
|
||||
<string name="fatal_error_msg">Applikasjonen fikk en kritisk feil og kan ikke fortsette</string>
|
||||
</resources>
|
6
src/android/java/res/values-nl/strings.xml
Normal file
6
src/android/java/res/values-nl/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">De Ministro service is niet gevonden.\nDe applicatie kan niet starten.</string>
|
||||
<string name="ministro_needed_msg">Deze applicatie maakt gebruik van de Ministro service. Wilt u deze installeren?</string>
|
||||
<string name="fatal_error_msg">Er is een fatale fout in de applicatie opgetreden. De applicatie kan niet verder gaan.</string>
|
||||
</resources>
|
6
src/android/java/res/values-pl/strings.xml
Normal file
6
src/android/java/res/values-pl/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Usługa Ministro nie została znaleziona.\nAplikacja nie może zostać uruchomiona.</string>
|
||||
<string name="ministro_needed_msg">Aplikacja wymaga usługi Ministro. Czy chcesz ją zainstalować?</string>
|
||||
<string name="fatal_error_msg">Wystąpił błąd krytyczny. Aplikacja zostanie zamknięta.</string>
|
||||
</resources>
|
6
src/android/java/res/values-pt-rBR/strings.xml
Normal file
6
src/android/java/res/values-pt-rBR/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Não foi possível encontrar o serviço Ministro.\nA aplicação não pode iniciar.</string>
|
||||
<string name="ministro_needed_msg">Essa aplicação requer o serviço Ministro. Gostaria de instalá-lo?</string>
|
||||
<string name="fatal_error_msg">Sua aplicação encontrou um erro fatal e não pode continuar.</string>
|
||||
</resources>
|
6
src/android/java/res/values-ro/strings.xml
Normal file
6
src/android/java/res/values-ro/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Serviciul Ministro nu poate fi găsit.\nAplicaţia nu poate porni.</string>
|
||||
<string name="ministro_needed_msg">Această aplicaţie necesită serviciul Ministro.\nDoriţi să-l instalaţi?</string>
|
||||
<string name="fatal_error_msg">Aplicaţia dumneavoastră a întâmpinat o eroare fatală şi nu poate continua.</string>
|
||||
</resources>
|
6
src/android/java/res/values-rs/strings.xml
Normal file
6
src/android/java/res/values-rs/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Ministro servise nije pronađen. Aplikacija ne može biti pokrenuta.</string>
|
||||
<string name="ministro_needed_msg">Ova aplikacija zahteva Ministro servis. Želite li da ga instalirate?</string>
|
||||
<string name="fatal_error_msg">Vaša aplikacija je naišla na fatalnu grešku i ne može nastaviti sa radom.</string>
|
||||
</resources>
|
6
src/android/java/res/values-ru/strings.xml
Normal file
6
src/android/java/res/values-ru/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">Сервис Ministro не найден.\nПриложение нельзя запустить.</string>
|
||||
<string name="ministro_needed_msg">Этому приложению необходим сервис Ministro. Вы хотите его установить?</string>
|
||||
<string name="fatal_error_msg">Ваше приложение столкнулось с фатальной ошибкой и не может более работать.</string>
|
||||
</resources>
|
6
src/android/java/res/values-zh-rCN/strings.xml
Normal file
6
src/android/java/res/values-zh-rCN/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">无法找到Ministro服务。\n应用程序无法启动。</string>
|
||||
<string name="ministro_needed_msg">此应用程序需要Ministro服务。您想安装它吗?</string>
|
||||
<string name="fatal_error_msg">您的应用程序遇到一个致命错误导致它无法继续。</string>
|
||||
</resources>
|
6
src/android/java/res/values-zh-rTW/strings.xml
Normal file
6
src/android/java/res/values-zh-rTW/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="ministro_not_found_msg">無法找到Ministro服務。\n應用程序無法啟動。</string>
|
||||
<string name="ministro_needed_msg">此應用程序需要Ministro服務。您想安裝它嗎?</string>
|
||||
<string name="fatal_error_msg">您的應用程序遇到一個致命錯誤導致它無法繼續。</string>
|
||||
</resources>
|
8
src/android/java/res/values/libs.xml
Normal file
8
src/android/java/res/values/libs.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<array name="qt_libs">
|
||||
<item>QtCore</item>
|
||||
<item>QtGui</item>
|
||||
</array>
|
||||
<array name="bundled_libs"/>
|
||||
</resources>
|
7
src/android/java/res/values/strings.xml
Normal file
7
src/android/java/res/values/strings.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name"></string>
|
||||
<string name="ministro_not_found_msg">Can\'t find Ministro service.\nThe application can\'t start.</string>
|
||||
<string name="ministro_needed_msg">This application requires Ministro service. Would you like to install it?</string>
|
||||
<string name="fatal_error_msg">Your application encountered a fatal error and cannot continue.</string>
|
||||
</resources>
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (c) 2012, BogDan Vatra <bogdan@kde.org>
|
||||
Contact: http://www.qt-project.org/legal
|
||||
|
||||
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.kde.necessitas.ministro;
|
||||
|
||||
import org.kde.necessitas.ministro.IMinistroCallback;
|
||||
|
||||
interface IMinistro
|
||||
{
|
||||
/**
|
||||
* Check/download required libs to run the application
|
||||
*
|
||||
* param callback - interface used by Minsitro service to notify the client when the loader is ready
|
||||
* param parameters
|
||||
* parameters fields:
|
||||
* * Key Name Key type Explanations
|
||||
* "required.modules" StringArray Required modules by your application
|
||||
* "application.title" String Application name, used to show more informations to user
|
||||
* "qt.provider" String Qt libs provider, currently only "necessitas" is supported.
|
||||
* "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 1 !
|
||||
* "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://doc.trolltech.com/4.8/qtglobal.html#QT_VERSION)!
|
||||
* "3rd.party.repositories" StringArray 3rd party repositories, which should be downloaded by ministro, needs minimum.ministro.api >= 2
|
||||
* Check http://community.kde.org/Necessitas/Ministro for more details.
|
||||
*/
|
||||
void requestLoader(in IMinistroCallback callback, in Bundle parameters);
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright (c) 2012, BogDan Vatra <bogdan@kde.org>
|
||||
Contact: http://www.qt-project.org/legal
|
||||
|
||||
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.kde.necessitas.ministro;
|
||||
|
||||
oneway interface IMinistroCallback {
|
||||
/**
|
||||
* This method is called by the Ministro service back into the application which
|
||||
* implements this interface.
|
||||
*
|
||||
* param in - loaderParams
|
||||
* loaderParams fields:
|
||||
* * Key Name Key type Explanations
|
||||
* * "error.code" Integer See below
|
||||
* * "error.message" String Missing if no error, otherwise will contain the error message translated into phone language where available.
|
||||
* * "dex.path" String The list of jar/apk files containing classes and resources, needed to be passed to application DexClassLoader
|
||||
* * "lib.path" String The list of directories containing native libraries; may be missing, needed to be passed to application DexClassLoader
|
||||
* * "loader.class.name" String Loader class name.
|
||||
*
|
||||
* "error.code" field possible errors:
|
||||
* - 0 no error.
|
||||
* - 1 incompatible Ministro version. Ministro needs to be upgraded.
|
||||
* - 2 not all modules could be satisfy.
|
||||
* - 3 invalid parameters
|
||||
*
|
||||
* This parameter will contain additional fields which are used by the loader to start your application, so it must be passed to loader.
|
||||
*/
|
||||
|
||||
void loaderReady(in Bundle loaderParams);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,149 @@
|
||||
/*
|
||||
Copyright (c) 2012, BogDan Vatra <bogdan@kde.org>
|
||||
Contact: http://www.qt-project.org/legal
|
||||
|
||||
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 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";
|
||||
public static Object m_delegateObject = null;
|
||||
public static HashMap<String, ArrayList<Method>> m_delegateMethods= new HashMap<String, ArrayList<Method>>();
|
||||
public static Method dispatchKeyEvent = null;
|
||||
public static Method dispatchPopulateAccessibilityEvent = null;
|
||||
public static Method dispatchTouchEvent = null;
|
||||
public static Method dispatchTrackballEvent = null;
|
||||
public static Method onKeyDown = null;
|
||||
public static Method onKeyMultiple = null;
|
||||
public static Method onKeyUp = null;
|
||||
public static Method onTouchEvent = null;
|
||||
public static Method onTrackballEvent = null;
|
||||
public static Method onActivityResult = null;
|
||||
public static Method onCreate = null;
|
||||
public static Method onKeyLongPress = null;
|
||||
public static Method dispatchKeyShortcutEvent = null;
|
||||
public static Method onKeyShortcut = null;
|
||||
public static Method dispatchGenericMotionEvent = null;
|
||||
public static Method onGenericMotionEvent = null;
|
||||
|
||||
public static void setQtActivityDelegate(Object listener)
|
||||
{
|
||||
QtApplication.m_delegateObject = listener;
|
||||
|
||||
ArrayList<Method> delegateMethods = new ArrayList<Method>();
|
||||
for (Method m : listener.getClass().getMethods()) {
|
||||
if (m.getDeclaringClass().getName().startsWith("org.qtproject.qt5.android"))
|
||||
delegateMethods.add(m);
|
||||
}
|
||||
|
||||
ArrayList<Field> applicationFields = new ArrayList<Field>();
|
||||
for (Field f : QtApplication.class.getFields()) {
|
||||
if (f.getDeclaringClass().getName().equals(QtApplication.class.getName()))
|
||||
applicationFields.add(f);
|
||||
}
|
||||
|
||||
for (Method delegateMethod : delegateMethods) {
|
||||
try {
|
||||
QtActivity.class.getDeclaredMethod(delegateMethod.getName(), delegateMethod.getParameterTypes());
|
||||
if (QtApplication.m_delegateMethods.containsKey(delegateMethod.getName())) {
|
||||
QtApplication.m_delegateMethods.get(delegateMethod.getName()).add(delegateMethod);
|
||||
} else {
|
||||
ArrayList<Method> delegateSet = new ArrayList<Method>();
|
||||
delegateSet.add(delegateMethod);
|
||||
QtApplication.m_delegateMethods.put(delegateMethod.getName(), delegateSet);
|
||||
}
|
||||
for (Field applicationField:applicationFields) {
|
||||
if (applicationField.getName().equals(delegateMethod.getName())) {
|
||||
try {
|
||||
applicationField.set(null, delegateMethod);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
if (m_delegateObject != null && m_delegateMethods.containsKey("onTerminate"))
|
||||
invokeDelegateMethod(m_delegateMethods.get("onTerminate").get(0));
|
||||
super.onTerminate();
|
||||
}
|
||||
|
||||
public static class InvokeResult
|
||||
{
|
||||
public boolean invoked = false;
|
||||
public Object methodReturns = null;
|
||||
}
|
||||
|
||||
private static int stackDeep=-1;
|
||||
public static InvokeResult invokeDelegate(Object... args)
|
||||
{
|
||||
InvokeResult result = new InvokeResult();
|
||||
if (m_delegateObject == null)
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
final String methodName=elements[stackDeep].getMethodName();
|
||||
if (-1 == stackDeep || !m_delegateMethods.containsKey(methodName))
|
||||
return result;
|
||||
|
||||
for (Method m : m_delegateMethods.get(methodName)) {
|
||||
if (m.getParameterTypes().length == args.length) {
|
||||
result.methodReturns = invokeDelegateMethod(m, args);
|
||||
result.invoked = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Object invokeDelegateMethod(Method m, Object... args)
|
||||
{
|
||||
try {
|
||||
return m.invoke(m_delegateObject, args);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
8
src/android/java/version.xml
Normal file
8
src/android/java/version.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<version value="3">
|
||||
<ignore>
|
||||
<file>AndroidManifest.xml</file>
|
||||
<file>libs.xml</file>
|
||||
<file>logo.png</file>
|
||||
<file>icon.png</file>
|
||||
</ignore>
|
||||
</version>
|
@ -89,7 +89,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF) && !defined(Q_OS_LINUX_ANDROID)
|
||||
#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF) && !defined(Q_OS_ANDROID)
|
||||
# include <langinfo.h>
|
||||
#endif
|
||||
|
||||
|
@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_TEXTCODEC
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_IOS) || defined(Q_OS_LINUX_ANDROID) || defined(Q_OS_QNX)
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_IOS) || defined(Q_OS_ANDROID) || defined(Q_OS_QNX)
|
||||
#define QT_LOCALE_IS_UTF8
|
||||
#endif
|
||||
|
||||
|
@ -16,6 +16,12 @@ win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x
|
||||
|
||||
QMAKE_DOCS = $$PWD/doc/qtcore.qdocconf
|
||||
|
||||
ANDROID_JAR_DEPENDENCIES = \
|
||||
jar/QtAndroid.jar
|
||||
ANDROID_LIB_DEPENDENCIES = \
|
||||
plugins/platforms/android/libqtforandroid.so \
|
||||
libs/libgnustl_shared.so
|
||||
|
||||
load(qt_module)
|
||||
|
||||
include(animation/animation.pri)
|
||||
|
@ -57,6 +57,10 @@
|
||||
#include <slog2.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -835,6 +839,24 @@ Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
|
||||
static QtMsgHandler msgHandler = 0; // pointer to debug handler (without context)
|
||||
static QtMessageHandler messageHandler = 0; // pointer to debug handler (with context)
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
static void android_default_message_handler(QtMsgType type,
|
||||
const QMessageLogContext &context,
|
||||
const QString &message)
|
||||
{
|
||||
android_LogPriority priority;
|
||||
switch (type) {
|
||||
case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break;
|
||||
case QtWarningMsg: priority = ANDROID_LOG_WARN; break;
|
||||
case QtCriticalMsg: priority = ANDROID_LOG_ERROR; break;
|
||||
case QtFatalMsg: priority = ANDROID_LOG_FATAL; break;
|
||||
};
|
||||
|
||||
__android_log_print(priority, "Qt", "%s:%d (%s): %s", qPrintable(context.file), context.line,
|
||||
qPrintable(context.function), qPrintable(message));
|
||||
}
|
||||
#endif //Q_OS_ANDROID
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
@ -855,6 +877,8 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con
|
||||
|
||||
#if defined(QT_USE_SLOG2)
|
||||
slog2_default_handler(type, logMessage.toLocal8Bit().constData());
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
android_default_message_handler(type, context, logMessage);
|
||||
#else
|
||||
fprintf(stderr, "%s", logMessage.toLocal8Bit().constData());
|
||||
fflush(stderr);
|
||||
|
@ -80,6 +80,7 @@
|
||||
LYNX - LynxOS
|
||||
BSD4 - Any BSD 4.4 system
|
||||
UNIX - Any UNIX BSD/SYSV system
|
||||
ANDROID - Android platform
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
|
||||
@ -90,6 +91,9 @@
|
||||
# else
|
||||
# define Q_OS_DARWIN32
|
||||
# endif
|
||||
#elif defined(ANDROID)
|
||||
# define Q_OS_ANDROID
|
||||
# define Q_OS_LINUX
|
||||
#elif defined(__CYGWIN__)
|
||||
# define Q_OS_CYGWIN
|
||||
#elif !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
|
||||
|
@ -133,7 +133,7 @@ win32 {
|
||||
SOURCES += io/qstandardpaths_unix.cpp
|
||||
}
|
||||
|
||||
linux-*|if(qnx:contains(QT_CONFIG, inotify)) {
|
||||
linux|if(qnx:contains(QT_CONFIG, inotify)) {
|
||||
SOURCES += io/qfilesystemwatcher_inotify.cpp
|
||||
HEADERS += io/qfilesystemwatcher_inotify_p.h
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
|
||||
if (entry.isEmpty() || entry.isRoot())
|
||||
return entry;
|
||||
|
||||
#if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && _POSIX_VERSION < 200809L
|
||||
#if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && _POSIX_VERSION < 200809L
|
||||
// realpath(X,0) is not supported
|
||||
Q_UNUSED(data);
|
||||
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
|
||||
|
@ -52,7 +52,7 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // mkdtemp
|
||||
#if defined(Q_OS_QNX) || defined(Q_OS_WIN)
|
||||
#if defined(Q_OS_QNX) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
|
||||
#include <private/qfilesystemengine_p.h>
|
||||
#endif
|
||||
|
||||
@ -94,9 +94,9 @@ static QString defaultTemplateName()
|
||||
return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX");
|
||||
}
|
||||
|
||||
#if defined(Q_OS_QNX ) || defined(Q_OS_WIN)
|
||||
static char *mkdtemp(char *templateName)
|
||||
static char *q_mkdtemp(char *templateName)
|
||||
{
|
||||
#if defined(Q_OS_QNX ) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
|
||||
static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
const size_t length = strlen(templateName);
|
||||
@ -137,17 +137,17 @@ static char *mkdtemp(char *templateName)
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#elif defined(Q_OS_LINUX_ANDROID)
|
||||
extern char *mkdtemp(char *);
|
||||
#else
|
||||
return mkdtemp(templateName);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QTemporaryDirPrivate::create(const QString &templateName)
|
||||
{
|
||||
QByteArray buffer = QFile::encodeName(templateName);
|
||||
if (!buffer.endsWith("XXXXXX"))
|
||||
buffer += "XXXXXX";
|
||||
if (mkdtemp(buffer.data())) { // modifies buffer
|
||||
if (q_mkdtemp(buffer.data())) { // modifies buffer
|
||||
success = true;
|
||||
path = QFile::decodeName(buffer.constData());
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ unix|integrity {
|
||||
|
||||
contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
|
||||
|
||||
!linux-android-* {
|
||||
!android {
|
||||
SOURCES += kernel/qsharedmemory_unix.cpp \
|
||||
kernel/qsystemsemaphore_unix.cpp
|
||||
} else {
|
||||
|
@ -69,7 +69,7 @@ namespace QSharedMemoryPrivate
|
||||
#include "qsystemsemaphore.h"
|
||||
#include "private/qobject_p.h"
|
||||
|
||||
#if !defined(Q_OS_WIN) && !defined(Q_OS_LINUX_ANDROID)
|
||||
#if !defined(Q_OS_WIN) && !defined(Q_OS_ANDROID)
|
||||
# include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
|
@ -287,7 +287,7 @@ static void setCurrentThreadName(pthread_t threadId, const char *name)
|
||||
|
||||
void *QThreadPrivate::start(void *arg)
|
||||
{
|
||||
#if !defined(Q_OS_LINUX_ANDROID)
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
#endif
|
||||
pthread_cleanup_push(QThreadPrivate::finish, arg);
|
||||
@ -326,7 +326,7 @@ void *QThreadPrivate::start(void *arg)
|
||||
#endif
|
||||
|
||||
emit thr->started(QThread::QPrivateSignal());
|
||||
#if !defined(Q_OS_LINUX_ANDROID)
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_testcancel();
|
||||
#endif
|
||||
@ -631,7 +631,7 @@ void QThread::start(Priority priority)
|
||||
|
||||
void QThread::terminate()
|
||||
{
|
||||
#if !defined(Q_OS_LINUX_ANDROID)
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
Q_D(QThread);
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
@ -673,7 +673,7 @@ void QThread::setTerminationEnabled(bool enabled)
|
||||
"Current thread was not started with QThread.");
|
||||
|
||||
Q_UNUSED(thr)
|
||||
#if defined(Q_OS_LINUX_ANDROID)
|
||||
#if defined(Q_OS_ANDROID)
|
||||
Q_UNUSED(enabled);
|
||||
#else
|
||||
pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
|
||||
|
@ -49,7 +49,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(Q_OS_LINUX_ANDROID)
|
||||
#if defined(Q_OS_ANDROID)
|
||||
// std::wstring is disabled on android's glibc, as bionic lacks certain features
|
||||
// that libstdc++ checks for (like mbcslen).
|
||||
namespace std
|
||||
|
@ -1507,10 +1507,20 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
|
||||
{
|
||||
QWindow *window = e->window.data();
|
||||
modifier_buttons = e->modifiers;
|
||||
if (e->nullWindow)
|
||||
if (e->nullWindow
|
||||
#ifdef Q_OS_ANDROID
|
||||
|| (e->keyType == QEvent::KeyRelease && e->key == Qt::Key_Back) || e->key == Qt::Key_Menu
|
||||
#endif
|
||||
) {
|
||||
window = QGuiApplication::focusWindow();
|
||||
if (!window)
|
||||
}
|
||||
if (!window
|
||||
#ifdef Q_OS_ANDROID
|
||||
&& e->keyType != QEvent::KeyRelease && e->key != Qt::Key_Back
|
||||
#endif
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (window->d_func()->blockedByModalWindow) {
|
||||
// a modal window is blocking this window, don't allow key events through
|
||||
return;
|
||||
@ -1520,7 +1530,19 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
|
||||
e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers,
|
||||
e->unicode, e->repeat, e->repeatCount);
|
||||
ev.setTimestamp(e->timestamp);
|
||||
QGuiApplication::sendSpontaneousEvent(window, &ev);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (e->keyType == QEvent::KeyRelease && e->key == Qt::Key_Back) {
|
||||
if (!window) {
|
||||
qApp->quit();
|
||||
} else {
|
||||
QGuiApplication::sendEvent(window, &ev);
|
||||
if (!ev.isAccepted() && e->key == Qt::Key_Back)
|
||||
QWindowSystemInterface::handleCloseEvent(window);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
QGuiApplication::sendSpontaneousEvent(window, &ev);
|
||||
}
|
||||
|
||||
void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e)
|
||||
|
@ -65,7 +65,11 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op,
|
||||
}
|
||||
|
||||
QUrl url = request.url();
|
||||
if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0 || url.isLocalFile()) {
|
||||
if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0
|
||||
#if defined(Q_OS_ANDROID)
|
||||
|| url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0
|
||||
#endif
|
||||
|| url.isLocalFile()) {
|
||||
return new QNetworkAccessFileBackend;
|
||||
} else if (!url.scheme().isEmpty() && url.authority().isEmpty() && (url.scheme().length() > 1)) {
|
||||
// check if QFile could, in theory, open this URL via the file engines
|
||||
@ -113,10 +117,16 @@ void QNetworkAccessFileBackend::open()
|
||||
|
||||
QString fileName = url.toLocalFile();
|
||||
if (fileName.isEmpty()) {
|
||||
if (url.scheme() == QLatin1String("qrc"))
|
||||
if (url.scheme() == QLatin1String("qrc")) {
|
||||
fileName = QLatin1Char(':') + url.path();
|
||||
else
|
||||
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
|
||||
} else {
|
||||
#if defined(Q_OS_ANDROID)
|
||||
if (url.scheme() == QLatin1String("assets"))
|
||||
fileName = QLatin1String("assets:") + url.path();
|
||||
else
|
||||
#endif
|
||||
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
|
||||
}
|
||||
}
|
||||
file.setFileName(fileName);
|
||||
|
||||
|
@ -1010,7 +1010,11 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|
||||
// fast path for GET on file:// URLs
|
||||
// The QNetworkAccessFileBackend will right now only be used for PUT
|
||||
if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
|
||||
&& (isLocalFile || scheme == QLatin1String("qrc"))) {
|
||||
&& (isLocalFile || scheme == QLatin1String("qrc")
|
||||
#if defined(Q_OS_ANDROID)
|
||||
|| scheme == QLatin1String("assets")
|
||||
#endif
|
||||
)) {
|
||||
return new QNetworkReplyFileImpl(this, req, op);
|
||||
}
|
||||
|
||||
|
@ -91,10 +91,16 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ
|
||||
|
||||
QString fileName = url.toLocalFile();
|
||||
if (fileName.isEmpty()) {
|
||||
if (url.scheme() == QLatin1String("qrc"))
|
||||
if (url.scheme() == QLatin1String("qrc")) {
|
||||
fileName = QLatin1Char(':') + url.path();
|
||||
else
|
||||
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
|
||||
} else {
|
||||
#if defined(Q_OS_ANDROID)
|
||||
if (url.scheme() == QLatin1String("assets"))
|
||||
fileName = QLatin1String("assets:") + url.path();
|
||||
else
|
||||
#endif
|
||||
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
|
||||
}
|
||||
}
|
||||
|
||||
QFileInfo fi(fileName);
|
||||
|
@ -27,7 +27,7 @@ SOURCES += kernel/qauthenticator.cpp \
|
||||
|
||||
unix:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
|
||||
|
||||
linux-android* {
|
||||
android {
|
||||
SOURCES -= kernel/qdnslookup_unix.cpp
|
||||
SOURCES += kernel/qdnslookup_android.cpp
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ QString QHostInfo::localHostName()
|
||||
|
||||
QString QHostInfo::localDomainName()
|
||||
{
|
||||
#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_LINUX_ANDROID)
|
||||
#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)
|
||||
resolveLibrary();
|
||||
if (local_res_ninit) {
|
||||
// using thread-safe version
|
||||
|
@ -61,7 +61,7 @@
|
||||
# define QT_NO_GETIFADDRS
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX_ANDROID
|
||||
#ifdef Q_OS_ANDROID
|
||||
// android lacks if_nameindex
|
||||
# define QT_NO_IPV6IFNAME
|
||||
#endif
|
||||
|
@ -681,10 +681,19 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
}
|
||||
#elif defined(Q_OS_UNIX)
|
||||
QSet<QString> certFiles;
|
||||
# ifdef Q_OS_ANDROID
|
||||
QList<QByteArray> directories;
|
||||
directories << qgetenv("MINISTRO_SSL_CERTS_PATH"); // Set by Ministro
|
||||
# else
|
||||
QList<QByteArray> directories = unixRootCertDirectories();
|
||||
# endif
|
||||
QDir currentDir;
|
||||
QStringList nameFilters;
|
||||
# ifdef Q_OS_ANDROID
|
||||
nameFilters << QLatin1String("*.der");
|
||||
#else
|
||||
nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
|
||||
# endif
|
||||
currentDir.setNameFilters(nameFilters);
|
||||
for (int a = 0; a < directories.count(); a++) {
|
||||
currentDir.setPath(QLatin1String(directories.at(a)));
|
||||
@ -697,10 +706,16 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
}
|
||||
QSetIterator<QString> it(certFiles);
|
||||
while(it.hasNext()) {
|
||||
systemCerts.append(QSslCertificate::fromPath(it.next()));
|
||||
# ifdef Q_OS_ANDROID
|
||||
systemCerts.append(QSslCertificate::fromPath(it.next(), QSsl::Der));
|
||||
# else
|
||||
systemCerts.append(QSslCertificate::fromPath(it.next(), QSsl::Pem));
|
||||
# endif
|
||||
}
|
||||
# ifndef Q_OS_ANDROID
|
||||
systemCerts.append(QSslCertificate::fromPath(QLatin1String("/etc/pki/tls/certs/ca-bundle.crt"), QSsl::Pem)); // Fedora, Mandriva
|
||||
systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/share/certs/ca-root-nss.crt"), QSsl::Pem)); // FreeBSD's ca_root_nss
|
||||
# endif
|
||||
#endif
|
||||
#ifdef QSSLSOCKET_DEBUG
|
||||
qDebug() << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
|
||||
|
@ -8,6 +8,9 @@ irix-cc*:QMAKE_CXXFLAGS += -no_prelink -ptused
|
||||
|
||||
QMAKE_DOCS = $$PWD/doc/qtopengl.qdocconf
|
||||
|
||||
ANDROID_LIB_DEPENDENCY_REPLACEMENTS = \
|
||||
"plugins/platforms/android/libqtforandroid.so:plugins/platforms/android/libqtforandroidGL.so"
|
||||
|
||||
load(qt_module)
|
||||
|
||||
contains(QT_CONFIG, opengl):CONFIG += opengl
|
||||
|
@ -1,4 +1,4 @@
|
||||
linux-*:contains(QT_CONFIG, evdev) {
|
||||
linux:contains(QT_CONFIG, evdev) {
|
||||
HEADERS += $$PWD/qdevicediscovery_p.h
|
||||
|
||||
contains(QT_CONFIG, libudev) {
|
||||
|
3
src/plugins/platforms/android/android.pro
Normal file
3
src/plugins/platforms/android/android.pro
Normal file
@ -0,0 +1,3 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += raster opengl
|
30
src/plugins/platforms/android/opengl/opengl.pro
Normal file
30
src/plugins/platforms/android/opengl/opengl.pro
Normal file
@ -0,0 +1,30 @@
|
||||
TARGET = qtforandroidGL
|
||||
|
||||
PLUGIN_TYPE = platforms
|
||||
load(qt_plugin)
|
||||
|
||||
# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp
|
||||
# Yes, the plugin imports itself statically
|
||||
DEFINES += QT_STATICPLUGIN ANDROID_PLUGIN_OPENGL
|
||||
|
||||
!equals(ANDROID_PLATFORM, android-9) {
|
||||
INCLUDEPATH += $$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/include
|
||||
LIBS += -L$$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/lib -ljnigraphics -landroid
|
||||
} else {
|
||||
LIBS += -ljnigraphics -landroid
|
||||
}
|
||||
|
||||
EGLFS_PLATFORM_HOOKS_SOURCES = $$PWD/../src/opengl/qeglfshooks_android.cpp
|
||||
|
||||
INCLUDEPATH += $$PWD/../src/opengl/
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/../src/opengl/qandroidopenglcontext.h \
|
||||
$$PWD/../src/opengl/qandroidopenglplatformwindow.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/../src/opengl/qandroidopenglcontext.cpp \
|
||||
$$PWD/../src/opengl/qandroidopenglplatformwindow.cpp
|
||||
|
||||
include($$PWD/../../eglfs/eglfs.pri)
|
||||
include($$PWD/../src/src.pri)
|
19
src/plugins/platforms/android/raster/raster.pro
Normal file
19
src/plugins/platforms/android/raster/raster.pro
Normal file
@ -0,0 +1,19 @@
|
||||
TARGET = qtforandroid
|
||||
|
||||
PLUGIN_TYPE = platforms
|
||||
|
||||
# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp
|
||||
# Yes, the plugin imports itself statically
|
||||
DEFINES += QT_STATICPLUGIN
|
||||
|
||||
load(qt_plugin)
|
||||
|
||||
!contains(ANDROID_PLATFORM, android-9) {
|
||||
INCLUDEPATH += $$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/include
|
||||
LIBS += -L$$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/lib -ljnigraphics -landroid
|
||||
} else {
|
||||
LIBS += -ljnigraphics -landroid
|
||||
}
|
||||
|
||||
include($$PWD/../src/src.pri)
|
||||
include($$PWD/../src/raster/raster.pri)
|
3
src/plugins/platforms/android/src/android.json
Normal file
3
src/plugins/platforms/android/src/android.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"Keys": [ "android" ]
|
||||
}
|
120
src/plugins/platforms/android/src/androidjniclipboard.cpp
Normal file
120
src/plugins/platforms/android/src/androidjniclipboard.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "androidjniclipboard.h"
|
||||
#include "androidjnimain.h"
|
||||
|
||||
using namespace QtAndroid;
|
||||
namespace QtAndroidClipboard
|
||||
{
|
||||
// Clipboard support
|
||||
static jmethodID m_registerClipboardManagerMethodID = 0;
|
||||
static jmethodID m_setClipboardTextMethodID = 0;
|
||||
static jmethodID m_hasClipboardTextMethodID = 0;
|
||||
static jmethodID m_getClipboardTextMethodID = 0;
|
||||
// Clipboard support
|
||||
|
||||
void setClipboardListener(QAndroidPlatformClipboard *listener)
|
||||
{
|
||||
Q_UNUSED(listener);
|
||||
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_registerClipboardManagerMethodID);
|
||||
}
|
||||
|
||||
void setClipboardText(const QString &text)
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
jstring jtext = env.jniEnv->NewString(reinterpret_cast<const jchar *>(text.data()),
|
||||
text.length());
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_setClipboardTextMethodID, jtext);
|
||||
env.jniEnv->DeleteLocalRef(jtext);
|
||||
}
|
||||
|
||||
bool hasClipboardText()
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return false;
|
||||
|
||||
return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_hasClipboardTextMethodID);
|
||||
}
|
||||
|
||||
QString clipboardText()
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return QString();
|
||||
|
||||
jstring text = reinterpret_cast<jstring>(env.jniEnv->CallStaticObjectMethod(applicationClass(),
|
||||
m_getClipboardTextMethodID));
|
||||
const jchar *jstr = env.jniEnv->GetStringChars(text, 0);
|
||||
QString str(reinterpret_cast<const QChar *>(jstr), env.jniEnv->GetStringLength(text));
|
||||
env.jniEnv->ReleaseStringChars(text, jstr);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
|
||||
VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
bool registerNatives(JNIEnv *env)
|
||||
{
|
||||
jclass appClass = QtAndroid::applicationClass();
|
||||
|
||||
GET_AND_CHECK_STATIC_METHOD(m_registerClipboardManagerMethodID, appClass, "registerClipboardManager", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_setClipboardTextMethodID, appClass, "setClipboardText", "(Ljava/lang/String;)V");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_hasClipboardTextMethodID, appClass, "hasClipboardText", "()Z");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_getClipboardTextMethodID, appClass, "getClipboardText", "()Ljava/lang/String;");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
61
src/plugins/platforms/android/src/androidjniclipboard.h
Normal file
61
src/plugins/platforms/android/src/androidjniclipboard.h
Normal file
@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ANDROIDJNICLIPBOARD_H
|
||||
#define ANDROIDJNICLIPBOARD_H
|
||||
|
||||
#include <jni.h>
|
||||
#include <QString>
|
||||
|
||||
class QAndroidPlatformClipboard;
|
||||
namespace QtAndroidClipboard
|
||||
{
|
||||
// Clipboard support
|
||||
void setClipboardListener(QAndroidPlatformClipboard *listener);
|
||||
void setClipboardText(const QString &text);
|
||||
bool hasClipboardText();
|
||||
QString clipboardText();
|
||||
// Clipboard support
|
||||
|
||||
bool registerNatives(JNIEnv *env);
|
||||
}
|
||||
|
||||
#endif // ANDROIDJNICLIPBOARD_H
|
480
src/plugins/platforms/android/src/androidjniinput.cpp
Normal file
480
src/plugins/platforms/android/src/androidjniinput.cpp
Normal file
@ -0,0 +1,480 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "androidjniinput.h"
|
||||
#include "androidjnimain.h"
|
||||
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QTouchEvent>
|
||||
#include <QPointer>
|
||||
|
||||
using namespace QtAndroid;
|
||||
|
||||
namespace QtAndroidInput
|
||||
{
|
||||
static jmethodID m_showSoftwareKeyboardMethodID = 0;
|
||||
static jmethodID m_resetSoftwareKeyboardMethodID = 0;
|
||||
static jmethodID m_hideSoftwareKeyboardMethodID = 0;
|
||||
static jmethodID m_isSoftwareKeyboardVisibleMethodID = 0;
|
||||
static jmethodID m_updateSelectionMethodID = 0;
|
||||
|
||||
static bool m_ignoreMouseEvents = false;
|
||||
|
||||
static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
|
||||
|
||||
static QPointer<QWindow> m_mouseGrabber;
|
||||
|
||||
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_updateSelectionMethodID,
|
||||
selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
}
|
||||
|
||||
void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints)
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(),
|
||||
m_showSoftwareKeyboardMethodID,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
inputHints);
|
||||
}
|
||||
|
||||
void resetSoftwareKeyboard()
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_resetSoftwareKeyboardMethodID);
|
||||
}
|
||||
|
||||
void hideSoftwareKeyboard()
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_hideSoftwareKeyboardMethodID);
|
||||
}
|
||||
|
||||
bool isSoftwareKeyboardVisible()
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return false;
|
||||
|
||||
return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_isSoftwareKeyboardVisibleMethodID);
|
||||
}
|
||||
|
||||
|
||||
static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
|
||||
{
|
||||
if (m_ignoreMouseEvents)
|
||||
return;
|
||||
|
||||
QPoint globalPos(x,y);
|
||||
QWindow *tlw = topLevelWindowAt(globalPos);
|
||||
m_mouseGrabber = tlw;
|
||||
QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos;
|
||||
QWindowSystemInterface::handleMouseEvent(tlw,
|
||||
localPos,
|
||||
globalPos,
|
||||
Qt::MouseButtons(Qt::LeftButton));
|
||||
}
|
||||
|
||||
static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
|
||||
{
|
||||
QPoint globalPos(x,y);
|
||||
QWindow *tlw = m_mouseGrabber.data();
|
||||
if (!tlw)
|
||||
tlw = topLevelWindowAt(globalPos);
|
||||
QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos;
|
||||
QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos
|
||||
, Qt::MouseButtons(Qt::NoButton));
|
||||
m_ignoreMouseEvents = false;
|
||||
m_mouseGrabber = 0;
|
||||
}
|
||||
|
||||
static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
|
||||
{
|
||||
|
||||
if (m_ignoreMouseEvents)
|
||||
return;
|
||||
|
||||
QPoint globalPos(x,y);
|
||||
QWindow *tlw = m_mouseGrabber.data();
|
||||
if (!tlw)
|
||||
tlw = topLevelWindowAt(globalPos);
|
||||
QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
|
||||
QWindowSystemInterface::handleMouseEvent(tlw,
|
||||
localPos,
|
||||
globalPos,
|
||||
Qt::MouseButtons(Qt::LeftButton));
|
||||
}
|
||||
|
||||
static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
|
||||
{
|
||||
m_ignoreMouseEvents = true;
|
||||
QPoint globalPos(x,y);
|
||||
QWindow *tlw = topLevelWindowAt(globalPos);
|
||||
QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
|
||||
|
||||
// Release left button
|
||||
QWindowSystemInterface::handleMouseEvent(tlw,
|
||||
localPos,
|
||||
globalPos,
|
||||
Qt::MouseButtons(Qt::NoButton));
|
||||
|
||||
// Press right button
|
||||
QWindowSystemInterface::handleMouseEvent(tlw,
|
||||
localPos,
|
||||
globalPos,
|
||||
Qt::MouseButtons(Qt::RightButton));
|
||||
}
|
||||
|
||||
static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/)
|
||||
{
|
||||
m_touchPoints.clear();
|
||||
}
|
||||
|
||||
static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, jfloat size, jfloat pressure)
|
||||
{
|
||||
Qt::TouchPointState state = Qt::TouchPointStationary;
|
||||
switch (action) {
|
||||
case 0:
|
||||
state = Qt::TouchPointPressed;
|
||||
break;
|
||||
case 1:
|
||||
state = Qt::TouchPointMoved;
|
||||
break;
|
||||
case 2:
|
||||
state = Qt::TouchPointStationary;
|
||||
break;
|
||||
case 3:
|
||||
state = Qt::TouchPointReleased;
|
||||
break;
|
||||
}
|
||||
|
||||
const int dw = desktopWidthPixels();
|
||||
const int dh = desktopHeightPixels();
|
||||
QWindowSystemInterface::TouchPoint touchPoint;
|
||||
touchPoint.id = id;
|
||||
touchPoint.pressure = pressure;
|
||||
touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
|
||||
touchPoint.state = state;
|
||||
touchPoint.area = QRectF(x - double(dw*size) / 2.0,
|
||||
y - double(dh*size) / 2.0,
|
||||
double(dw*size),
|
||||
double(dh*size));
|
||||
m_touchPoints.push_back(touchPoint);
|
||||
}
|
||||
|
||||
static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint action)
|
||||
{
|
||||
QEvent::Type eventType = QEvent::None;
|
||||
switch (action) {
|
||||
case 0:
|
||||
eventType = QEvent::TouchBegin;
|
||||
break;
|
||||
case 1:
|
||||
eventType = QEvent::TouchUpdate;
|
||||
break;
|
||||
case 2:
|
||||
eventType = QEvent::TouchEnd;
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// QWindowSystemInterface::handleTouchEvent(0, 0, eventType, QTouchEvent::TouchScreen, m_touchPoints);
|
||||
}
|
||||
|
||||
static int mapAndroidKey(int key)
|
||||
{
|
||||
// 0--9 0x00000007 -- 0x00000010
|
||||
if (key >= 0x00000007 && key <= 0x00000010)
|
||||
return Qt::Key_0 + key - 0x00000007;
|
||||
|
||||
// A--Z 0x0000001d -- 0x00000036
|
||||
if (key >= 0x0000001d && key <= 0x00000036)
|
||||
return Qt::Key_A + key - 0x0000001d;
|
||||
|
||||
switch (key) {
|
||||
case 0x00000039:
|
||||
case 0x0000003a:
|
||||
return Qt::Key_Alt;
|
||||
|
||||
case 0x0000004b:
|
||||
return Qt::Key_Apostrophe;
|
||||
|
||||
case 0x00000004: // KEYCODE_BACK
|
||||
return Qt::Key_Back;
|
||||
|
||||
case 0x00000049:
|
||||
return Qt::Key_Backslash;
|
||||
|
||||
case 0x00000005:
|
||||
return Qt::Key_Call;
|
||||
|
||||
case 0x0000001b:
|
||||
return Qt::Key_WebCam;
|
||||
|
||||
case 0x0000001c:
|
||||
return Qt::Key_Clear;
|
||||
|
||||
case 0x00000037:
|
||||
return Qt::Key_Comma;
|
||||
|
||||
case 0x00000043:
|
||||
return Qt::Key_Backspace;
|
||||
|
||||
case 0x00000017: // KEYCODE_DPAD_CENTER
|
||||
return Qt::Key_Enter;
|
||||
|
||||
case 0x00000014: // KEYCODE_DPAD_DOWN
|
||||
return Qt::Key_Down;
|
||||
|
||||
case 0x00000015: //KEYCODE_DPAD_LEFT
|
||||
return Qt::Key_Left;
|
||||
|
||||
case 0x00000016: //KEYCODE_DPAD_RIGHT
|
||||
return Qt::Key_Right;
|
||||
|
||||
case 0x00000013: //KEYCODE_DPAD_UP
|
||||
return Qt::Key_Up;
|
||||
|
||||
case 0x00000006: //KEYCODE_ENDCALL
|
||||
return Qt::Key_Hangup;
|
||||
|
||||
case 0x00000042:
|
||||
return Qt::Key_Return;
|
||||
|
||||
case 0x00000041: //KEYCODE_ENVELOPE
|
||||
return Qt::Key_LaunchMail;
|
||||
|
||||
case 0x00000046:
|
||||
return Qt::Key_Equal;
|
||||
|
||||
case 0x00000040:
|
||||
return Qt::Key_Explorer;
|
||||
|
||||
case 0x00000003:
|
||||
return Qt::Key_Home;
|
||||
|
||||
case 0x00000047:
|
||||
return Qt::Key_BracketLeft;
|
||||
|
||||
case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD
|
||||
return Qt::Key_Forward;
|
||||
|
||||
case 0x00000057:
|
||||
return Qt::Key_MediaNext;
|
||||
|
||||
case 0x00000055:
|
||||
return Qt::Key_MediaPlay;
|
||||
|
||||
case 0x00000058:
|
||||
return Qt::Key_MediaPrevious;
|
||||
|
||||
case 0x00000059:
|
||||
return Qt::Key_AudioRewind;
|
||||
|
||||
case 0x00000056:
|
||||
return Qt::Key_MediaStop;
|
||||
|
||||
case 0x00000052: //KEYCODE_MENU
|
||||
return Qt::Key_Menu;
|
||||
|
||||
case 0x00000045:
|
||||
return Qt::Key_Minus;
|
||||
|
||||
case 0x0000005b:
|
||||
return Qt::Key_VolumeMute;
|
||||
|
||||
case 0x0000004e:
|
||||
return Qt::Key_NumLock;
|
||||
|
||||
case 0x00000038:
|
||||
return Qt::Key_Period;
|
||||
|
||||
case 0x00000051:
|
||||
return Qt::Key_Plus;
|
||||
|
||||
case 0x0000001a:
|
||||
return Qt::Key_PowerOff;
|
||||
|
||||
case 0x00000048:
|
||||
return Qt::Key_BracketRight;
|
||||
|
||||
case 0x00000054:
|
||||
return Qt::Key_Search;
|
||||
|
||||
case 0x0000004a:
|
||||
return Qt::Key_Semicolon;
|
||||
|
||||
case 0x0000003b:
|
||||
case 0x0000003c:
|
||||
return Qt::Key_Shift;
|
||||
|
||||
case 0x0000004c:
|
||||
return Qt::Key_Slash;
|
||||
|
||||
case 0x00000001:
|
||||
return Qt::Key_Left;
|
||||
|
||||
case 0x00000002:
|
||||
return Qt::Key_Right;
|
||||
|
||||
case 0x0000003e:
|
||||
return Qt::Key_Space;
|
||||
|
||||
case 0x0000003f: // KEYCODE_SYM
|
||||
return Qt::Key_Meta;
|
||||
|
||||
case 0x0000003d:
|
||||
return Qt::Key_Tab;
|
||||
|
||||
case 0x00000019:
|
||||
return Qt::Key_VolumeDown;
|
||||
|
||||
case 0x00000018:
|
||||
return Qt::Key_VolumeUp;
|
||||
|
||||
case 0x00000000: // KEYCODE_UNKNOWN
|
||||
case 0x00000011: // KEYCODE_STAR ?!?!?
|
||||
case 0x00000012: // KEYCODE_POUND ?!?!?
|
||||
case 0x00000053: // KEYCODE_NOTIFICATION ?!?!?
|
||||
case 0x0000004f: // KEYCODE_HEADSETHOOK ?!?!?
|
||||
case 0x00000044: // KEYCODE_GRAVE ?!?!?
|
||||
case 0x00000050: // KEYCODE_FOCUS ?!?!?
|
||||
return Qt::Key_Any;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier)
|
||||
{
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
if (modifier & 1)
|
||||
modifiers |= Qt::ShiftModifier;
|
||||
|
||||
if (modifier & 2)
|
||||
modifiers |= Qt::AltModifier;
|
||||
|
||||
if (modifier & 4)
|
||||
modifiers |= Qt::MetaModifier;
|
||||
|
||||
QWindowSystemInterface::handleKeyEvent(0,
|
||||
QEvent::KeyPress,
|
||||
mapAndroidKey(key),
|
||||
modifiers,
|
||||
QChar(unicode),
|
||||
true);
|
||||
}
|
||||
|
||||
static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier)
|
||||
{
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
if (modifier & 1)
|
||||
modifiers |= Qt::ShiftModifier;
|
||||
|
||||
if (modifier & 2)
|
||||
modifiers |= Qt::AltModifier;
|
||||
|
||||
if (modifier & 4)
|
||||
modifiers |= Qt::MetaModifier;
|
||||
|
||||
QWindowSystemInterface::handleKeyEvent(0,
|
||||
QEvent::KeyRelease,
|
||||
mapAndroidKey(key),
|
||||
modifiers,
|
||||
QChar(unicode),
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"touchBegin","(I)V",(void*)touchBegin},
|
||||
{"touchAdd","(IIIZIIFF)V",(void*)touchAdd},
|
||||
{"touchEnd","(II)V",(void*)touchEnd},
|
||||
{"mouseDown", "(III)V", (void *)mouseDown},
|
||||
{"mouseUp", "(III)V", (void *)mouseUp},
|
||||
{"mouseMove", "(III)V", (void *)mouseMove},
|
||||
{"longPress", "(III)V", (void *)longPress},
|
||||
{"keyDown", "(III)V", (void *)keyDown},
|
||||
{"keyUp", "(III)V", (void *)keyUp}
|
||||
};
|
||||
|
||||
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
|
||||
VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
bool registerNatives(JNIEnv *env)
|
||||
{
|
||||
jclass appClass = QtAndroid::applicationClass();
|
||||
|
||||
if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
|
||||
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
GET_AND_CHECK_STATIC_METHOD(m_showSoftwareKeyboardMethodID, appClass, "showSoftwareKeyboard", "(IIIII)V");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_resetSoftwareKeyboardMethodID, appClass, "resetSoftwareKeyboard", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_hideSoftwareKeyboardMethodID, appClass, "hideSoftwareKeyboard", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_isSoftwareKeyboardVisibleMethodID, appClass, "isSoftwareKeyboardVisible", "()Z");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_updateSelectionMethodID, appClass, "updateSelection", "(IIII)V");
|
||||
return true;
|
||||
}
|
||||
}
|
59
src/plugins/platforms/android/src/androidjniinput.h
Normal file
59
src/plugins/platforms/android/src/androidjniinput.h
Normal file
@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ANDROIDJNIINPUT_H
|
||||
#define ANDROIDJNIINPUT_H
|
||||
#include <jni.h>
|
||||
|
||||
namespace QtAndroidInput
|
||||
{
|
||||
// Software keyboard support
|
||||
void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints);
|
||||
void resetSoftwareKeyboard();
|
||||
void hideSoftwareKeyboard();
|
||||
bool isSoftwareKeyboardVisible();
|
||||
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd);
|
||||
// Software keyboard support
|
||||
|
||||
bool registerNatives(JNIEnv *env);
|
||||
}
|
||||
|
||||
#endif // ANDROIDJNIINPUT_H
|
839
src/plugins/platforms/android/src/androidjnimain.cpp
Normal file
839
src/plugins/platforms/android/src/androidjnimain.cpp
Normal file
@ -0,0 +1,839 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <qcoreapplication.h>
|
||||
#include <qimage.h>
|
||||
#include <qpoint.h>
|
||||
#include <qplugin.h>
|
||||
#include <qsemaphore.h>
|
||||
#include <qmutex.h>
|
||||
#include <qdebug.h>
|
||||
#include <qglobal.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "androidjnimain.h"
|
||||
#include "androidjniinput.h"
|
||||
#include "androidjniclipboard.h"
|
||||
#include "androidjnimenu.h"
|
||||
#include "qandroidplatformintegration.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <qabstracteventdispatcher.h>
|
||||
|
||||
#include <android/bitmap.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#include "qandroidassetsfileenginehandler.h"
|
||||
#include <android/api-level.h>
|
||||
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
|
||||
#ifdef ANDROID_PLUGIN_OPENGL
|
||||
# include "qandroidopenglplatformwindow.h"
|
||||
#endif
|
||||
|
||||
#if __ANDROID_API__ > 8
|
||||
# include <android/native_window_jni.h>
|
||||
#endif
|
||||
|
||||
static jmethodID m_redrawSurfaceMethodID = 0;
|
||||
|
||||
Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin)
|
||||
|
||||
static JavaVM *m_javaVM = NULL;
|
||||
static jclass m_applicationClass = NULL;
|
||||
static jobject m_classLoaderObject = NULL;
|
||||
static jmethodID m_loadClassMethodID = NULL;
|
||||
static AAssetManager *m_assetManager = NULL;
|
||||
static jobject m_resourcesObj;
|
||||
static jobject m_activityObject = NULL;
|
||||
|
||||
static jclass m_bitmapClass = 0;
|
||||
static jmethodID m_createBitmapMethodID = 0;
|
||||
static jobject m_ARGB_8888_BitmapConfigValue = 0;
|
||||
static jobject m_RGB_565_BitmapConfigValue = 0;
|
||||
|
||||
static jclass m_bitmapDrawableClass = 0;
|
||||
static jmethodID m_bitmapDrawableConstructorMethodID = 0;
|
||||
|
||||
extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application
|
||||
static Main m_main = NULL;
|
||||
static void *m_mainLibraryHnd = NULL;
|
||||
static QList<QByteArray> m_applicationParams;
|
||||
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
static jobject m_surface = NULL;
|
||||
#else
|
||||
static EGLNativeWindowType m_nativeWindow = 0;
|
||||
static QSemaphore m_waitForWindowSemaphore;
|
||||
static bool m_waitForWindow = false;
|
||||
|
||||
static jfieldID m_surfaceFieldID = 0;
|
||||
#endif
|
||||
|
||||
|
||||
static QSemaphore m_quitAppSemaphore;
|
||||
static QMutex m_surfaceMutex(QMutex::Recursive);
|
||||
static QSemaphore m_pauseApplicationSemaphore;
|
||||
static QMutex m_pauseApplicationMutex;
|
||||
|
||||
static QAndroidPlatformIntegration *m_androidPlatformIntegration = 0;
|
||||
|
||||
static int m_desktopWidthPixels = 0;
|
||||
static int m_desktopHeightPixels = 0;
|
||||
|
||||
static volatile bool m_pauseApplication;
|
||||
|
||||
static jmethodID m_setFullScreenMethodID = 0;
|
||||
|
||||
static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = 0;
|
||||
|
||||
|
||||
|
||||
static const char m_qtTag[] = "Qt";
|
||||
static const char m_classErrorMsg[] = "Can't find class \"%s\"";
|
||||
static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
|
||||
|
||||
static inline void checkPauseApplication()
|
||||
{
|
||||
m_pauseApplicationMutex.lock();
|
||||
if (m_pauseApplication) {
|
||||
m_pauseApplicationMutex.unlock();
|
||||
m_pauseApplicationSemaphore.acquire(); // wait until surface is created
|
||||
|
||||
m_pauseApplicationMutex.lock();
|
||||
m_pauseApplication = false;
|
||||
m_pauseApplicationMutex.unlock();
|
||||
|
||||
//FIXME
|
||||
// QWindowSystemInterface::handleScreenAvailableGeometryChange(0);
|
||||
// QWindowSystemInterface::handleScreenGeometryChange(0);
|
||||
} else {
|
||||
m_pauseApplicationMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
namespace QtAndroid
|
||||
{
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
void flushImage(const QPoint &pos, const QImage &image, const QRect &destinationRect)
|
||||
{
|
||||
checkPauseApplication();
|
||||
QMutexLocker locker(&m_surfaceMutex);
|
||||
if (!m_surface)
|
||||
return;
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
int bpp = 2;
|
||||
AndroidBitmapInfo info;
|
||||
int ret;
|
||||
|
||||
if ((ret = AndroidBitmap_getInfo(env.jniEnv, m_surface, &info)) < 0) {
|
||||
qWarning() << "AndroidBitmap_getInfo() failed ! error=" << ret;
|
||||
m_javaVM->DetachCurrentThread();
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) {
|
||||
qWarning() << "Bitmap format is not RGB_565!";
|
||||
m_javaVM->DetachCurrentThread();
|
||||
return;
|
||||
}
|
||||
|
||||
void *pixels;
|
||||
unsigned char *screenBits;
|
||||
if ((ret = AndroidBitmap_lockPixels(env.jniEnv, m_surface, &pixels)) < 0) {
|
||||
qWarning() << "AndroidBitmap_lockPixels() failed! error=" << ret;
|
||||
m_javaVM->DetachCurrentThread();
|
||||
return;
|
||||
}
|
||||
|
||||
screenBits = static_cast<unsigned char *>(pixels);
|
||||
int sbpl = info.stride;
|
||||
int swidth = info.width;
|
||||
int sheight = info.height;
|
||||
|
||||
unsigned sposx = pos.x() + destinationRect.x();
|
||||
unsigned sposy = pos.y() + destinationRect.y();
|
||||
|
||||
screenBits += sposy * sbpl;
|
||||
|
||||
unsigned ibpl = image.bytesPerLine();
|
||||
unsigned iposx = destinationRect.x();
|
||||
unsigned iposy = destinationRect.y();
|
||||
|
||||
const unsigned char *imageBits = static_cast<const unsigned char *>(image.bits());
|
||||
imageBits += iposy * ibpl;
|
||||
|
||||
unsigned width = swidth - sposx < unsigned(destinationRect.width())
|
||||
? (swidth-sposx)
|
||||
: destinationRect.width();
|
||||
unsigned height = sheight - sposy < unsigned(destinationRect.height())
|
||||
? (sheight - sposy)
|
||||
: destinationRect.height();
|
||||
|
||||
for (unsigned y = 0; y < height; y++) {
|
||||
memcpy(screenBits + y*sbpl + sposx*bpp,
|
||||
imageBits + y*ibpl + iposx*bpp,
|
||||
width*bpp);
|
||||
}
|
||||
AndroidBitmap_unlockPixels(env.jniEnv, m_surface);
|
||||
|
||||
env.jniEnv->CallStaticVoidMethod(m_applicationClass,
|
||||
m_redrawSurfaceMethodID,
|
||||
jint(destinationRect.left()),
|
||||
jint(destinationRect.top()),
|
||||
jint(destinationRect.right() + 1),
|
||||
jint(destinationRect.bottom() + 1));
|
||||
#warning FIXME dirty hack, figure out why it needs to add 1 to right and bottom !!!!
|
||||
}
|
||||
|
||||
#else // for #ifndef ANDROID_PLUGIN_OPENGL
|
||||
EGLNativeWindowType nativeWindow(bool waitForWindow)
|
||||
{
|
||||
m_surfaceMutex.lock();
|
||||
if (!m_nativeWindow && waitForWindow) {
|
||||
m_waitForWindow = true;
|
||||
m_surfaceMutex.unlock();
|
||||
m_waitForWindowSemaphore.acquire();
|
||||
m_waitForWindow = false;
|
||||
return m_nativeWindow;
|
||||
}
|
||||
m_surfaceMutex.unlock();
|
||||
return m_nativeWindow;
|
||||
}
|
||||
|
||||
QSize nativeWindowSize()
|
||||
{
|
||||
if (m_nativeWindow == 0)
|
||||
return QAndroidPlatformIntegration::defaultDesktopSize();
|
||||
|
||||
int width = ANativeWindow_getWidth(m_nativeWindow);
|
||||
int height = ANativeWindow_getHeight(m_nativeWindow);
|
||||
|
||||
return QSize(width, height);
|
||||
}
|
||||
#endif
|
||||
|
||||
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
|
||||
{
|
||||
m_surfaceMutex.lock();
|
||||
m_androidPlatformIntegration = androidPlatformIntegration;
|
||||
m_surfaceMutex.unlock();
|
||||
}
|
||||
|
||||
void setFullScreen(QWidget *widget)
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return;
|
||||
|
||||
bool fullScreen = widget->isFullScreen();
|
||||
if (!fullScreen) {
|
||||
foreach (QWidget *w, qApp->topLevelWidgets()) {
|
||||
fullScreen |= w->isFullScreen();
|
||||
if (fullScreen)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_setFullScreenMethodID, fullScreen);
|
||||
}
|
||||
|
||||
QWindow *topLevelWindowAt(const QPoint &globalPos)
|
||||
{
|
||||
return m_androidPlatformIntegration
|
||||
? m_androidPlatformIntegration->screen()->topLevelAt(globalPos)
|
||||
: 0;
|
||||
}
|
||||
|
||||
int desktopWidthPixels()
|
||||
{
|
||||
return m_desktopWidthPixels;
|
||||
}
|
||||
|
||||
int desktopHeightPixels()
|
||||
{
|
||||
return m_desktopHeightPixels;
|
||||
}
|
||||
|
||||
JavaVM *javaVM()
|
||||
{
|
||||
return m_javaVM;
|
||||
}
|
||||
|
||||
jclass findClass(const QString &className, JNIEnv *env)
|
||||
{
|
||||
return static_cast<jclass>(env->CallObjectMethod(m_classLoaderObject,
|
||||
m_loadClassMethodID,
|
||||
env->NewString(reinterpret_cast<const jchar *>(className.constData()),
|
||||
jsize(className.length()))));
|
||||
}
|
||||
|
||||
AAssetManager *assetManager()
|
||||
{
|
||||
return m_assetManager;
|
||||
}
|
||||
|
||||
jclass applicationClass()
|
||||
{
|
||||
return m_applicationClass;
|
||||
}
|
||||
|
||||
jobject activity()
|
||||
{
|
||||
return m_activityObject;
|
||||
}
|
||||
|
||||
jobject createBitmap(QImage img, JNIEnv *env)
|
||||
{
|
||||
if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB16)
|
||||
img = img.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass,
|
||||
m_createBitmapMethodID,
|
||||
img.width(),
|
||||
img.height(),
|
||||
img.format() == QImage::Format_ARGB32
|
||||
? m_ARGB_8888_BitmapConfigValue
|
||||
: m_RGB_565_BitmapConfigValue);
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
AndroidBitmapInfo info;
|
||||
if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
|
||||
env->DeleteLocalRef(bitmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *pixels;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
|
||||
env->DeleteLocalRef(bitmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.stride == uint(img.bytesPerLine())
|
||||
&& info.width == uint(img.width())
|
||||
&& info.height == uint(img.height())) {
|
||||
memcpy(pixels, img.constBits(), info.stride * info.height);
|
||||
} else {
|
||||
uchar *bmpPtr = static_cast<uchar *>(pixels);
|
||||
const unsigned width = qMin(info.width, (uint)img.width()); //should be the same
|
||||
const unsigned height = qMin(info.height, (uint)img.height()); //should be the same
|
||||
for (unsigned y = 0; y < height; y++, bmpPtr += info.stride)
|
||||
memcpy(bmpPtr, img.constScanLine(y), width);
|
||||
}
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env)
|
||||
{
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
return env->NewObject(m_bitmapDrawableClass,
|
||||
m_bitmapDrawableConstructorMethodID,
|
||||
m_resourcesObj,
|
||||
bitmap);
|
||||
}
|
||||
|
||||
const char *classErrorMsgFmt()
|
||||
{
|
||||
return m_classErrorMsg;
|
||||
}
|
||||
|
||||
const char *methodErrorMsgFmt()
|
||||
{
|
||||
return m_methodErrorMsg;
|
||||
}
|
||||
|
||||
const char *qtTagText()
|
||||
{
|
||||
return m_qtTag;
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/)
|
||||
{
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
m_surface = 0;
|
||||
#else
|
||||
m_nativeWindow = 0;
|
||||
m_waitForWindow = false;
|
||||
#endif
|
||||
|
||||
m_androidPlatformIntegration = 0;
|
||||
m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler();
|
||||
|
||||
#ifdef ANDROID_PLUGIN_OPENGL
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *startMainMethod(void */*data*/)
|
||||
{
|
||||
char const **params;
|
||||
params = static_cast<char const **>(malloc(m_applicationParams.length() * sizeof(char *)));
|
||||
for (int i = 0; i < m_applicationParams.size(); i++)
|
||||
params[i] = static_cast<const char *>(m_applicationParams[i].constData());
|
||||
|
||||
int ret = m_main(m_applicationParams.length(), const_cast<char **>(params));
|
||||
|
||||
free(params);
|
||||
Q_UNUSED(ret);
|
||||
|
||||
if (m_mainLibraryHnd) {
|
||||
int res = dlclose(m_mainLibraryHnd);
|
||||
if (res < 0)
|
||||
qWarning() << "dlclose failed:" << dlerror();
|
||||
}
|
||||
|
||||
QtAndroid::AttachedJNIEnv env;
|
||||
if (!env.jniEnv)
|
||||
return 0;
|
||||
|
||||
if (m_applicationClass) {
|
||||
jmethodID quitApp = env.jniEnv->GetStaticMethodID(m_applicationClass, "quitApp", "()V");
|
||||
env.jniEnv->CallStaticVoidMethod(m_applicationClass, quitApp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString)
|
||||
{
|
||||
m_mainLibraryHnd = NULL;
|
||||
const char *nativeString = env->GetStringUTFChars(environmentString, 0);
|
||||
QByteArray string = nativeString;
|
||||
env->ReleaseStringUTFChars(environmentString, nativeString);
|
||||
m_applicationParams=string.split('\t');
|
||||
foreach (string, m_applicationParams) {
|
||||
if (putenv(string.constData()))
|
||||
qWarning() << "Can't set environment" << string;
|
||||
}
|
||||
|
||||
nativeString = env->GetStringUTFChars(paramsString, 0);
|
||||
string = nativeString;
|
||||
env->ReleaseStringUTFChars(paramsString, nativeString);
|
||||
|
||||
m_applicationParams=string.split('\t');
|
||||
|
||||
// Go home
|
||||
QDir::setCurrent(QDir::homePath());
|
||||
|
||||
//look for main()
|
||||
if (m_applicationParams.length()) {
|
||||
// Obtain a handle to the main library (the library that contains the main() function).
|
||||
// This library should already be loaded, and calling dlopen() will just return a reference to it.
|
||||
m_mainLibraryHnd = dlopen(m_applicationParams.first().data(), 0);
|
||||
if (m_mainLibraryHnd == NULL) {
|
||||
qCritical() << "dlopen failed:" << dlerror();
|
||||
return false;
|
||||
}
|
||||
m_main = (Main)dlsym(m_mainLibraryHnd, "main");
|
||||
} else {
|
||||
qWarning() << "No main library was specified; searching entire process (this is slow!)";
|
||||
m_main = (Main)dlsym(RTLD_DEFAULT, "main");
|
||||
}
|
||||
|
||||
if (!m_main) {
|
||||
qCritical() << "dlsym failed:" << dlerror();
|
||||
qCritical() << "Could not find main method";
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_t appThread;
|
||||
return pthread_create(&appThread, NULL, startMainMethod, NULL) == 0;
|
||||
}
|
||||
|
||||
static void pauseQtApp(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
m_surfaceMutex.lock();
|
||||
m_pauseApplicationMutex.lock();
|
||||
|
||||
if (m_androidPlatformIntegration)
|
||||
m_androidPlatformIntegration->pauseApp();
|
||||
m_pauseApplication = true;
|
||||
|
||||
m_pauseApplicationMutex.unlock();
|
||||
m_surfaceMutex.unlock();
|
||||
}
|
||||
|
||||
static void resumeQtApp(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
m_surfaceMutex.lock();
|
||||
m_pauseApplicationMutex.lock();
|
||||
if (m_androidPlatformIntegration)
|
||||
m_androidPlatformIntegration->resumeApp();
|
||||
|
||||
if (m_pauseApplication)
|
||||
m_pauseApplicationSemaphore.release();
|
||||
|
||||
m_pauseApplicationMutex.unlock();
|
||||
m_surfaceMutex.unlock();
|
||||
}
|
||||
|
||||
static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/)
|
||||
{
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
if (m_surface) {
|
||||
env->DeleteGlobalRef(m_surface);
|
||||
m_surface = 0;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(env);
|
||||
#endif
|
||||
|
||||
m_androidPlatformIntegration = 0;
|
||||
delete m_androidAssetsFileEngineHandler;
|
||||
}
|
||||
|
||||
static void terminateQt(JNIEnv *env, jclass /*clazz*/)
|
||||
{
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
if (m_surface)
|
||||
env->DeleteGlobalRef(m_surface);
|
||||
#endif
|
||||
env->DeleteGlobalRef(m_applicationClass);
|
||||
env->DeleteGlobalRef(m_classLoaderObject);
|
||||
env->DeleteGlobalRef(m_resourcesObj);
|
||||
env->DeleteGlobalRef(m_activityObject);
|
||||
env->DeleteGlobalRef(m_bitmapClass);
|
||||
env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue);
|
||||
env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue);
|
||||
env->DeleteGlobalRef(m_bitmapDrawableClass);
|
||||
}
|
||||
|
||||
#ifdef ANDROID_PLUGIN_OPENGL
|
||||
#if __ANDROID_API__ < 9
|
||||
struct FakeNativeWindow
|
||||
{
|
||||
long long dummyNativeWindow;// force 64 bits alignment
|
||||
};
|
||||
|
||||
class FakeSurface: public FakeNativeWindow
|
||||
{
|
||||
public:
|
||||
virtual void FakeSurfaceMethod()
|
||||
{
|
||||
fakeSurface = 0;
|
||||
}
|
||||
|
||||
int fakeSurface;
|
||||
};
|
||||
|
||||
EGLNativeWindowType ANativeWindow_fromSurface(JNIEnv *env, jobject jSurface)
|
||||
{
|
||||
FakeSurface *surface = static_cast<FakeSurface *>(env->GetIntField(jSurface, m_surfaceFieldID));
|
||||
return static_cast<EGLNativeWindowType>(static_cast<FakeNativeWindow*>(surface));
|
||||
}
|
||||
#endif // __ANDROID_API__ < 9
|
||||
#endif // ANDROID_PLUGIN_OPENGL
|
||||
|
||||
static void setSurface(JNIEnv *env, jobject /*thiz*/, jobject jSurface)
|
||||
{
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
if (m_surface)
|
||||
env->DeleteGlobalRef(m_surface);
|
||||
m_surface = env->NewGlobalRef(jSurface);
|
||||
#else
|
||||
m_surfaceMutex.lock();
|
||||
EGLNativeWindowType nativeWindow = ANativeWindow_fromSurface(env, jSurface);
|
||||
bool sameNativeWindow = (nativeWindow != 0 && nativeWindow == m_nativeWindow);
|
||||
|
||||
m_nativeWindow = nativeWindow;
|
||||
if (m_waitForWindow)
|
||||
m_waitForWindowSemaphore.release();
|
||||
if (m_androidPlatformIntegration && !sameNativeWindow) {
|
||||
m_surfaceMutex.unlock();
|
||||
m_androidPlatformIntegration->surfaceChanged();
|
||||
} else if (m_androidPlatformIntegration && sameNativeWindow) {
|
||||
QAndroidOpenGLPlatformWindow *window = m_androidPlatformIntegration->primaryWindow();
|
||||
QPlatformScreen *screen = m_androidPlatformIntegration->screen();
|
||||
QSize size = QtAndroid::nativeWindowSize();
|
||||
|
||||
QRect geometry(QPoint(0, 0), size);
|
||||
QWindowSystemInterface::handleScreenAvailableGeometryChange(screen->screen(), geometry);
|
||||
QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), geometry);
|
||||
|
||||
if (window != 0) {
|
||||
window->lock();
|
||||
window->scheduleResize(size);
|
||||
|
||||
QWindowSystemInterface::handleExposeEvent(window->window(),
|
||||
QRegion(window->window()->geometry()));
|
||||
window->unlock();
|
||||
}
|
||||
|
||||
m_surfaceMutex.unlock();
|
||||
} else {
|
||||
m_surfaceMutex.unlock();
|
||||
}
|
||||
#endif // for #ifndef ANDROID_PLUGIN_OPENGL
|
||||
}
|
||||
|
||||
static void destroySurface(JNIEnv *env, jobject /*thiz*/)
|
||||
{
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
if (m_surface) {
|
||||
env->DeleteGlobalRef(m_surface);
|
||||
m_surface = 0;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(env);
|
||||
m_nativeWindow = 0;
|
||||
if (m_androidPlatformIntegration != 0)
|
||||
m_androidPlatformIntegration->invalidateNativeSurface();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/,
|
||||
jint /*widthPixels*/, jint /*heightPixels*/,
|
||||
jint desktopWidthPixels, jint desktopHeightPixels,
|
||||
jdouble xdpi, jdouble ydpi)
|
||||
{
|
||||
m_desktopWidthPixels = desktopWidthPixels;
|
||||
m_desktopHeightPixels = desktopHeightPixels;
|
||||
|
||||
if (!m_androidPlatformIntegration) {
|
||||
QAndroidPlatformIntegration::setDefaultDisplayMetrics(desktopWidthPixels,desktopHeightPixels,
|
||||
qRound(double(desktopWidthPixels) / xdpi * 25.4),
|
||||
qRound(double(desktopHeightPixels) / ydpi * 25.4));
|
||||
} else {
|
||||
m_androidPlatformIntegration->setDisplayMetrics(qRound(double(desktopWidthPixels) / xdpi * 25.4),
|
||||
qRound(double(desktopHeightPixels) / ydpi * 25.4));
|
||||
m_androidPlatformIntegration->setDesktopSize(desktopWidthPixels, desktopHeightPixels);
|
||||
}
|
||||
}
|
||||
|
||||
static void lockSurface(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
m_surfaceMutex.lock();
|
||||
}
|
||||
|
||||
static void unlockSurface(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
m_surfaceMutex.unlock();
|
||||
}
|
||||
|
||||
static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidPlatformIntegration)
|
||||
return;
|
||||
|
||||
if (qApp != 0) {
|
||||
foreach (QWidget *w, qApp->topLevelWidgets())
|
||||
w->update();
|
||||
}
|
||||
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());
|
||||
QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
|
||||
#else
|
||||
qWarning("updateWindow: Dirty screen not implemented yet on OpenGL");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newOrientation)
|
||||
{
|
||||
if (m_androidPlatformIntegration == 0)
|
||||
return;
|
||||
|
||||
Qt::ScreenOrientation screenOrientation = newOrientation == 1
|
||||
? Qt::PortraitOrientation
|
||||
: Qt::LandscapeOrientation;
|
||||
QPlatformScreen *screen = m_androidPlatformIntegration->screen();
|
||||
QWindowSystemInterface::handleScreenOrientationChange(screen->screen(),
|
||||
screenOrientation);
|
||||
}
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin},
|
||||
{"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication},
|
||||
{"pauseQtApp", "()V", (void *)pauseQtApp},
|
||||
{"resumeQtApp", "()V", (void *)resumeQtApp},
|
||||
{"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin},
|
||||
{"terminateQt", "()V", (void *)terminateQt},
|
||||
{"setDisplayMetrics", "(IIIIDD)V", (void *)setDisplayMetrics},
|
||||
{"setSurface", "(Ljava/lang/Object;)V", (void *)setSurface},
|
||||
{"destroySurface", "()V", (void *)destroySurface},
|
||||
{"lockSurface", "()V", (void *)lockSurface},
|
||||
{"unlockSurface", "()V", (void *)unlockSurface},
|
||||
{"updateWindow", "()V", (void *)updateWindow},
|
||||
{"handleOrientationChanged", "(I)V", (void *)handleOrientationChanged}
|
||||
};
|
||||
|
||||
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
|
||||
clazz = env->FindClass(CLASS_NAME); \
|
||||
if (!clazz) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
|
||||
return JNI_FALSE; \
|
||||
}
|
||||
|
||||
#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
|
||||
VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
return JNI_FALSE; \
|
||||
}
|
||||
|
||||
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
|
||||
VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
return JNI_FALSE; \
|
||||
}
|
||||
|
||||
#define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
|
||||
VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
|
||||
return JNI_FALSE; \
|
||||
}
|
||||
|
||||
#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
|
||||
VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
|
||||
return JNI_FALSE; \
|
||||
}
|
||||
|
||||
static int registerNatives(JNIEnv *env)
|
||||
{
|
||||
jclass clazz;
|
||||
FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative");
|
||||
m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
|
||||
|
||||
if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
|
||||
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
GET_AND_CHECK_STATIC_METHOD(m_redrawSurfaceMethodID, m_applicationClass, "redrawSurface", "(IIII)V");
|
||||
GET_AND_CHECK_STATIC_METHOD(m_setFullScreenMethodID, m_applicationClass, "setFullScreen", "(Z)V");
|
||||
|
||||
#ifdef ANDROID_PLUGIN_OPENGL
|
||||
FIND_AND_CHECK_CLASS("android/view/Surface");
|
||||
#if __ANDROID_API__ < 9
|
||||
# define ANDROID_VIEW_SURFACE_JNI_ID "mSurface"
|
||||
#else
|
||||
# define ANDROID_VIEW_SURFACE_JNI_ID "mNativeSurface"
|
||||
#endif
|
||||
GET_AND_CHECK_FIELD(m_surfaceFieldID, clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
|
||||
#endif
|
||||
|
||||
jmethodID methodID;
|
||||
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
|
||||
jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
|
||||
m_activityObject = env->NewGlobalRef(activityObject);
|
||||
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;");
|
||||
|
||||
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));
|
||||
|
||||
GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
|
||||
m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(activityObject, methodID));
|
||||
|
||||
FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
|
||||
m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
|
||||
GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass
|
||||
, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
|
||||
|
||||
FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
|
||||
jfieldID fieldId;
|
||||
GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
|
||||
m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
|
||||
GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
|
||||
m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
|
||||
|
||||
FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
|
||||
m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
|
||||
GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID,
|
||||
m_bitmapDrawableClass,
|
||||
"<init>",
|
||||
"(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
|
||||
{
|
||||
typedef union {
|
||||
JNIEnv *nativeEnvironment;
|
||||
void *venv;
|
||||
} UnionJNIEnvToVoid;
|
||||
|
||||
__android_log_print(ANDROID_LOG_INFO, "Qt", "qt start");
|
||||
UnionJNIEnvToVoid uenv;
|
||||
uenv.venv = NULL;
|
||||
m_javaVM = 0;
|
||||
|
||||
if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
JNIEnv *env = uenv.nativeEnvironment;
|
||||
if (!registerNatives(env)
|
||||
|| !QtAndroidInput::registerNatives(env)
|
||||
|| !QtAndroidClipboard::registerNatives(env)
|
||||
|| !QtAndroidMenu::registerNatives(env)) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_javaVM = vm;
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
120
src/plugins/platforms/android/src/androidjnimain.h
Normal file
120
src/plugins/platforms/android/src/androidjnimain.h
Normal file
@ -0,0 +1,120 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ANDROID_APP_H
|
||||
#define ANDROID_APP_H
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#ifdef ANDROID_PLUGIN_OPENGL
|
||||
# include <EGL/eglplatform.h>
|
||||
#endif
|
||||
|
||||
#include <QtCore/qsize.h>
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/asset_manager.h>
|
||||
|
||||
class QImage;
|
||||
class QRect;
|
||||
class QPoint;
|
||||
class QThread;
|
||||
class QAndroidPlatformIntegration;
|
||||
class QWidget;
|
||||
class QString;
|
||||
class QWindow;
|
||||
|
||||
namespace QtAndroid
|
||||
{
|
||||
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
|
||||
void setQtThread(QThread *thread);
|
||||
|
||||
void setFullScreen(QWidget *widget);
|
||||
|
||||
#ifndef ANDROID_PLUGIN_OPENGL
|
||||
void flushImage(const QPoint &pos, const QImage &image, const QRect &rect);
|
||||
#else
|
||||
EGLNativeWindowType nativeWindow(bool waitToCreate = true);
|
||||
QSize nativeWindowSize();
|
||||
#endif
|
||||
|
||||
QWindow *topLevelWindowAt(const QPoint &globalPos);
|
||||
int desktopWidthPixels();
|
||||
int desktopHeightPixels();
|
||||
JavaVM *javaVM();
|
||||
jclass findClass(const QString &className, JNIEnv *env);
|
||||
AAssetManager *assetManager();
|
||||
jclass applicationClass();
|
||||
jobject activity();
|
||||
|
||||
jobject createBitmap(QImage img, JNIEnv *env = 0);
|
||||
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0);
|
||||
|
||||
struct AttachedJNIEnv
|
||||
{
|
||||
AttachedJNIEnv()
|
||||
{
|
||||
attached = false;
|
||||
if (QtAndroid::javaVM()->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) < 0) {
|
||||
if (QtAndroid::javaVM()->AttachCurrentThread(&jniEnv, NULL) < 0) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Qt", "AttachCurrentThread failed");
|
||||
jniEnv = 0;
|
||||
return;
|
||||
}
|
||||
attached = true;
|
||||
}
|
||||
}
|
||||
|
||||
~AttachedJNIEnv()
|
||||
{
|
||||
if (attached)
|
||||
QtAndroid::javaVM()->DetachCurrentThread();
|
||||
}
|
||||
bool attached;
|
||||
JNIEnv *jniEnv;
|
||||
};
|
||||
const char *classErrorMsgFmt();
|
||||
const char *methodErrorMsgFmt();
|
||||
const char *qtTagText();
|
||||
|
||||
}
|
||||
#endif // ANDROID_APP_H
|
405
src/plugins/platforms/android/src/androidjnimenu.cpp
Normal file
405
src/plugins/platforms/android/src/androidjnimenu.cpp
Normal file
@ -0,0 +1,405 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "androidjnimenu.h"
|
||||
#include "androidjnimain.h"
|
||||
#include <qmutex.h>
|
||||
#include <qset.h>
|
||||
#include <qqueue.h>
|
||||
#include <android/log.h>
|
||||
#include "qandroidplatformmenubar.h"
|
||||
#include "qandroidplatformmenu.h"
|
||||
#include <qandroidplatformmenuitem.h>
|
||||
|
||||
using namespace QtAndroid;
|
||||
|
||||
namespace QtAndroidMenu
|
||||
{
|
||||
static QQueue<QAndroidPlatformMenu *> pendingContextMenus;
|
||||
static QAndroidPlatformMenu *visibleMenu = 0;
|
||||
static QMutex visibleMenuMutex(QMutex::Recursive);
|
||||
|
||||
static QSet<QAndroidPlatformMenuBar *> menuBars;
|
||||
static QAndroidPlatformMenuBar *visibleMenuBar = 0;
|
||||
static QWindow *activeTopLevelWindow = 0;
|
||||
static QMutex menuBarMutex(QMutex::Recursive);
|
||||
|
||||
static jmethodID openContextMenuMethodID = 0;
|
||||
static jmethodID closeContextMenuMethodID = 0;
|
||||
static jmethodID resetOptionsMenuMethodID = 0;
|
||||
|
||||
static jmethodID clearMenuMethodID = 0;
|
||||
static jmethodID addMenuItemMethodID = 0;
|
||||
static int menuNoneValue = 0;
|
||||
static jmethodID setHeaderTitleContextMenuMethodID = 0;
|
||||
|
||||
static jmethodID setCheckableMenuItemMethodID = 0;
|
||||
static jmethodID setCheckedMenuItemMethodID = 0;
|
||||
static jmethodID setEnabledMenuItemMethodID = 0;
|
||||
static jmethodID setIconMenuItemMethodID = 0;
|
||||
static jmethodID setVisibleMenuItemMethodID = 0;
|
||||
|
||||
void resetMenuBar()
|
||||
{
|
||||
AttachedJNIEnv env;
|
||||
if (env.jniEnv)
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), resetOptionsMenuMethodID);
|
||||
}
|
||||
|
||||
void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env)
|
||||
{
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (visibleMenu) {
|
||||
pendingContextMenus.enqueue(menu);
|
||||
} else {
|
||||
visibleMenu = menu;
|
||||
menu->aboutToShow();
|
||||
if (env) {
|
||||
env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
|
||||
} else {
|
||||
AttachedJNIEnv aenv;
|
||||
if (aenv.jniEnv)
|
||||
aenv.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hideContextMenu(QAndroidPlatformMenu *menu)
|
||||
{
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (visibleMenu == menu) {
|
||||
AttachedJNIEnv env;
|
||||
if (env.jniEnv)
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
|
||||
} else {
|
||||
pendingContextMenus.removeOne(menu);
|
||||
}
|
||||
}
|
||||
|
||||
void syncMenu(QAndroidPlatformMenu */*menu*/)
|
||||
{
|
||||
// QMutexLocker lock(&visibleMenuMutex);
|
||||
// if (visibleMenu == menu)
|
||||
// {
|
||||
// hideContextMenu(menu);
|
||||
// showContextMenu(menu);
|
||||
// }
|
||||
}
|
||||
|
||||
void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu)
|
||||
{
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (visibleMenu == menu)
|
||||
visibleMenu = 0;
|
||||
}
|
||||
|
||||
void setMenuBar(QAndroidPlatformMenuBar *menuBar, QWindow *window)
|
||||
{
|
||||
if (activeTopLevelWindow == window && visibleMenuBar != menuBar) {
|
||||
visibleMenuBar = menuBar;
|
||||
resetMenuBar();
|
||||
}
|
||||
}
|
||||
|
||||
void setActiveTopLevelWindow(QWindow *window)
|
||||
{
|
||||
QMutexLocker lock(&menuBarMutex);
|
||||
if (activeTopLevelWindow == window)
|
||||
return;
|
||||
|
||||
visibleMenuBar = 0;
|
||||
activeTopLevelWindow = window;
|
||||
#ifdef ANDROID_PLUGIN_OPENGL
|
||||
//only one toplevel window, so the menu bar always belongs to us
|
||||
if (menuBars.size() == 1) {
|
||||
visibleMenuBar = *menuBars.constBegin(); //since QSet doesn't have first()
|
||||
} else
|
||||
#endif
|
||||
foreach (QAndroidPlatformMenuBar *menuBar, menuBars) {
|
||||
if (menuBar->parentWindow() == window) {
|
||||
visibleMenuBar = menuBar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resetMenuBar();
|
||||
}
|
||||
|
||||
void addMenuBar(QAndroidPlatformMenuBar *menuBar)
|
||||
{
|
||||
QMutexLocker lock(&menuBarMutex);
|
||||
menuBars.insert(menuBar);
|
||||
}
|
||||
|
||||
void removeMenuBar(QAndroidPlatformMenuBar *menuBar)
|
||||
{
|
||||
QMutexLocker lock(&menuBarMutex);
|
||||
menuBars.remove(menuBar);
|
||||
if (visibleMenuBar == menuBar)
|
||||
resetMenuBar();
|
||||
}
|
||||
|
||||
static void fillMenuItem(JNIEnv *env, jobject menuItem, bool checkable, bool checked, bool enabled, bool visible, const QIcon &icon=QIcon())
|
||||
{
|
||||
env->CallObjectMethod(menuItem, setCheckableMenuItemMethodID, checkable);
|
||||
env->CallObjectMethod(menuItem, setCheckedMenuItemMethodID, checked);
|
||||
env->CallObjectMethod(menuItem, setEnabledMenuItemMethodID, enabled);
|
||||
|
||||
if (!icon.isNull()) {
|
||||
int sz = qMax(36, qgetenv("QT_ANDROID_APP_ICON_SIZE").toInt());
|
||||
QImage img = icon.pixmap(QSize(sz,sz),
|
||||
enabled
|
||||
? QIcon::Normal
|
||||
: QIcon::Disabled,
|
||||
QIcon::On).toImage();
|
||||
env->CallObjectMethod(menuItem,
|
||||
setIconMenuItemMethodID,
|
||||
createBitmapDrawable(createBitmap(img, env), env));
|
||||
}
|
||||
|
||||
env->CallObjectMethod(menuItem, setVisibleMenuItemMethodID, visible);
|
||||
}
|
||||
|
||||
static int addAllMenuItemsToMenu(JNIEnv *env, jobject menu, QAndroidPlatformMenu *platformMenu) {
|
||||
int order = 0;
|
||||
QMutexLocker lock(platformMenu->menuItemsMutex());
|
||||
foreach (QAndroidPlatformMenuItem *item, platformMenu->menuItems()) {
|
||||
if (item->isSeparator())
|
||||
continue;
|
||||
jstring jtext = env->NewString(reinterpret_cast<const jchar *>(item->text().data()),
|
||||
item->text().length());
|
||||
jobject menuItem = env->CallObjectMethod(menu,
|
||||
addMenuItemMethodID,
|
||||
menuNoneValue,
|
||||
int(item->tag()),
|
||||
order++,
|
||||
jtext);
|
||||
env->DeleteLocalRef(jtext);
|
||||
fillMenuItem(env,
|
||||
menuItem,
|
||||
item->isCheckable(),
|
||||
item->isChecked(),
|
||||
item->isEnabled(),
|
||||
item->isVisible(),
|
||||
item->icon());
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
|
||||
{
|
||||
env->CallVoidMethod(menu, clearMenuMethodID);
|
||||
QMutexLocker lock(&menuBarMutex);
|
||||
if (!visibleMenuBar)
|
||||
return JNI_FALSE;
|
||||
|
||||
const QAndroidPlatformMenuBar::PlatformMenusType &menus = visibleMenuBar->menus();
|
||||
int order = 0;
|
||||
QMutexLocker lockMenuBarMutex(visibleMenuBar->menusListMutex());
|
||||
if (menus.size() == 1) { // Expand the menu
|
||||
order = addAllMenuItemsToMenu(env, menu, static_cast<QAndroidPlatformMenu *>(menus.front()));
|
||||
} else {
|
||||
foreach (QAndroidPlatformMenu *item, menus) {
|
||||
jstring jtext = env->NewString(reinterpret_cast<const jchar *>(item->text().data()),
|
||||
item->text().length());
|
||||
jobject menuItem = env->CallObjectMethod(menu,
|
||||
addMenuItemMethodID,
|
||||
menuNoneValue,
|
||||
int(item->tag()),
|
||||
order++,
|
||||
jtext);
|
||||
env->DeleteLocalRef(jtext);
|
||||
|
||||
fillMenuItem(env,
|
||||
menuItem,
|
||||
false,
|
||||
false,
|
||||
item->isEnabled(),
|
||||
item->isVisible(),
|
||||
item->icon());
|
||||
}
|
||||
}
|
||||
return order ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
static jboolean onOptionsItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
|
||||
{
|
||||
QMutexLocker lock(&menuBarMutex);
|
||||
if (!visibleMenuBar)
|
||||
return JNI_FALSE;
|
||||
|
||||
const QAndroidPlatformMenuBar::PlatformMenusType &menus = visibleMenuBar->menus();
|
||||
if (menus.size() == 1) { // Expanded menu
|
||||
QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForTag(menuId));
|
||||
if (item) {
|
||||
if (item->menu()) {
|
||||
showContextMenu(item->menu(), env);
|
||||
} else {
|
||||
if (item->isCheckable())
|
||||
item->setChecked(checked);
|
||||
item->activated();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForTag(menuId));
|
||||
if (menu)
|
||||
showContextMenu(menu, env);
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static void onOptionsMenuClosed(JNIEnv */*env*/, jobject /*thiz*/, jobject /*menu*/)
|
||||
{
|
||||
}
|
||||
|
||||
static void onCreateContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
|
||||
{
|
||||
env->CallVoidMethod(menu, clearMenuMethodID);
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (!visibleMenu)
|
||||
return;
|
||||
|
||||
jstring jtext = env->NewString(reinterpret_cast<const jchar*>(visibleMenu->text().data()),
|
||||
visibleMenu->text().length());
|
||||
env->CallObjectMethod(menu, setHeaderTitleContextMenuMethodID, jtext);
|
||||
env->DeleteLocalRef(jtext);
|
||||
addAllMenuItemsToMenu(env, menu, visibleMenu);
|
||||
}
|
||||
|
||||
static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
|
||||
{
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForTag(menuId));
|
||||
if (item) {
|
||||
if (item->menu()) {
|
||||
showContextMenu(item->menu(), env);
|
||||
} else {
|
||||
if (item->isCheckable())
|
||||
item->setChecked(checked);
|
||||
item->activated();
|
||||
}
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static void onContextMenuClosed(JNIEnv *env, jobject /*thiz*/, jobject /*menu*/)
|
||||
{
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (!visibleMenu)
|
||||
return;
|
||||
visibleMenu->aboutToHide();
|
||||
visibleMenu = 0;
|
||||
if (!pendingContextMenus.empty())
|
||||
showContextMenu(pendingContextMenus.dequeue(), env);
|
||||
}
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"onPrepareOptionsMenu", "(Landroid/view/Menu;)Z", (void *)onPrepareOptionsMenu},
|
||||
{"onOptionsItemSelected", "(IZ)Z", (void *)onOptionsItemSelected},
|
||||
{"onOptionsMenuClosed", "(Landroid/view/Menu;)V", (void*)onOptionsMenuClosed},
|
||||
{"onCreateContextMenu", "(Landroid/view/ContextMenu;)V", (void *)onCreateContextMenu},
|
||||
{"onContextItemSelected", "(IZ)Z", (void *)onContextItemSelected},
|
||||
{"onContextMenuClosed", "(Landroid/view/Menu;)V", (void*)onContextMenuClosed},
|
||||
};
|
||||
|
||||
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
|
||||
clazz = env->FindClass(CLASS_NAME); \
|
||||
if (!clazz) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, qtTagText(), classErrorMsgFmt(), CLASS_NAME); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
|
||||
VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
|
||||
VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
|
||||
VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
|
||||
if (!VAR) { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), FIELD_NAME, FIELD_SIGNATURE); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
bool registerNatives(JNIEnv *env)
|
||||
{
|
||||
jclass appClass = applicationClass();
|
||||
|
||||
if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
|
||||
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(closeContextMenuMethodID, appClass, "closeContextMenu", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(resetOptionsMenuMethodID, appClass, "resetOptionsMenu", "()V");
|
||||
|
||||
jclass clazz;
|
||||
FIND_AND_CHECK_CLASS("android/view/Menu");
|
||||
GET_AND_CHECK_METHOD(clearMenuMethodID, clazz, "clear", "()V");
|
||||
GET_AND_CHECK_METHOD(addMenuItemMethodID, clazz, "add", "(IIILjava/lang/CharSequence;)Landroid/view/MenuItem;");
|
||||
jfieldID menuNoneFiledId;
|
||||
GET_AND_CHECK_STATIC_FIELD(menuNoneFiledId, clazz, "NONE", "I");
|
||||
menuNoneValue = env->GetStaticIntField(clazz, menuNoneFiledId);
|
||||
|
||||
FIND_AND_CHECK_CLASS("android/view/ContextMenu");
|
||||
GET_AND_CHECK_METHOD(setHeaderTitleContextMenuMethodID, clazz, "setHeaderTitle","(Ljava/lang/CharSequence;)Landroid/view/ContextMenu;");
|
||||
|
||||
FIND_AND_CHECK_CLASS("android/view/MenuItem");
|
||||
GET_AND_CHECK_METHOD(setCheckableMenuItemMethodID, clazz, "setCheckable", "(Z)Landroid/view/MenuItem;");
|
||||
GET_AND_CHECK_METHOD(setCheckedMenuItemMethodID, clazz, "setChecked", "(Z)Landroid/view/MenuItem;");
|
||||
GET_AND_CHECK_METHOD(setEnabledMenuItemMethodID, clazz, "setEnabled", "(Z)Landroid/view/MenuItem;");
|
||||
GET_AND_CHECK_METHOD(setIconMenuItemMethodID, clazz, "setIcon", "(Landroid/graphics/drawable/Drawable;)Landroid/view/MenuItem;");
|
||||
GET_AND_CHECK_METHOD(setVisibleMenuItemMethodID, clazz, "setVisible", "(Z)Landroid/view/MenuItem;");
|
||||
return true;
|
||||
}
|
||||
}
|
69
src/plugins/platforms/android/src/androidjnimenu.h
Normal file
69
src/plugins/platforms/android/src/androidjnimenu.h
Normal file
@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ANDROIDJNIMENU_H
|
||||
#define ANDROIDJNIMENU_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
class QAndroidPlatformMenuBar;
|
||||
class QAndroidPlatformMenu;
|
||||
class QAndroidPlatformMenuItem;
|
||||
class QWindow;
|
||||
|
||||
namespace QtAndroidMenu
|
||||
{
|
||||
// Menu support
|
||||
void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env = 0);
|
||||
void hideContextMenu(QAndroidPlatformMenu *menu);
|
||||
void syncMenu(QAndroidPlatformMenu *menu);
|
||||
void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu);
|
||||
|
||||
void setMenuBar(QAndroidPlatformMenuBar *menuBar, QWindow *window);
|
||||
void setActiveTopLevelWindow(QWindow *window);
|
||||
void addMenuBar(QAndroidPlatformMenuBar *menuBar);
|
||||
void removeMenuBar(QAndroidPlatformMenuBar *menuBar);
|
||||
|
||||
// Menu support
|
||||
bool registerNatives(JNIEnv *env);
|
||||
}
|
||||
|
||||
#endif // ANDROIDJNIMENU_H
|
66
src/plugins/platforms/android/src/androidplatformplugin.cpp
Normal file
66
src/plugins/platforms/android/src/androidplatformplugin.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <qpa/qplatformintegrationplugin.h>
|
||||
#include "qandroidplatformintegration.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QAndroidPlatformIntegrationPlugin: public QPlatformIntegrationPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "android.json")
|
||||
public:
|
||||
QPlatformIntegration *create(const QString &key, const QStringList ¶mList);
|
||||
};
|
||||
|
||||
|
||||
QPlatformIntegration *QAndroidPlatformIntegrationPlugin::create(const QString &key, const QStringList ¶mList)
|
||||
{
|
||||
Q_UNUSED(paramList);
|
||||
if (key.toLower() == "android")
|
||||
return new QAndroidPlatformIntegration(paramList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
#include "androidplatformplugin.moc"
|
||||
|
@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qandroidopenglcontext.h"
|
||||
#include "qandroidopenglplatformwindow.h"
|
||||
#include "qandroidplatformintegration.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QAndroidOpenGLContext::QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration,
|
||||
const QSurfaceFormat &format,
|
||||
QPlatformOpenGLContext *share,
|
||||
EGLDisplay display,
|
||||
EGLenum eglApi)
|
||||
: QEglFSContext(format, share, display, eglApi)
|
||||
, m_platformIntegration(integration)
|
||||
{
|
||||
}
|
||||
|
||||
void QAndroidOpenGLContext::swapBuffers(QPlatformSurface *surface)
|
||||
{
|
||||
QEglFSContext::swapBuffers(surface);
|
||||
|
||||
QAndroidOpenGLPlatformWindow *primaryWindow = m_platformIntegration->primaryWindow();
|
||||
if (primaryWindow == surface) {
|
||||
primaryWindow->lock();
|
||||
QSize size = primaryWindow->scheduledResize();
|
||||
if (size.isValid()) {
|
||||
QRect geometry(QPoint(0, 0), size);
|
||||
primaryWindow->setGeometry(geometry);
|
||||
primaryWindow->scheduleResize(QSize());
|
||||
}
|
||||
primaryWindow->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QANDROIDOPENGLCONTEXT_H
|
||||
#define QANDROIDOPENGLCONTEXT_H
|
||||
|
||||
#include <QtCore/qreadwritelock.h>
|
||||
#include "qeglfscontext.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QAndroidPlatformIntegration;
|
||||
class QAndroidOpenGLContext : public QEglFSContext
|
||||
{
|
||||
public:
|
||||
QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration,
|
||||
const QSurfaceFormat &format,
|
||||
QPlatformOpenGLContext *share,
|
||||
EGLDisplay display,
|
||||
EGLenum eglApi = EGL_OPENGL_ES_API);
|
||||
|
||||
void swapBuffers(QPlatformSurface *surface);
|
||||
|
||||
private:
|
||||
const QAndroidPlatformIntegration *m_platformIntegration;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QANDROIDOPENGLCONTEXT_H
|
@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qandroidopenglplatformwindow.h"
|
||||
#include "androidjnimain.h"
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QAndroidOpenGLPlatformWindow::QAndroidOpenGLPlatformWindow(QWindow *window)
|
||||
: QEglFSWindow(window)
|
||||
{
|
||||
}
|
||||
|
||||
bool QAndroidOpenGLPlatformWindow::isExposed() const
|
||||
{
|
||||
return QtAndroid::nativeWindow(false) != 0 && QEglFSWindow::isExposed();
|
||||
}
|
||||
|
||||
void QAndroidOpenGLPlatformWindow::invalidateSurface()
|
||||
{
|
||||
QWindowSystemInterface::handleExposeEvent(window(), QRegion()); // Obscure event
|
||||
QWindowSystemInterface::flushWindowSystemEvents();
|
||||
QEglFSWindow::invalidateSurface();
|
||||
}
|
||||
|
||||
void QAndroidOpenGLPlatformWindow::resetSurface()
|
||||
{
|
||||
QEglFSWindow::resetSurface();
|
||||
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event
|
||||
QWindowSystemInterface::flushWindowSystemEvents();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QANDROIDOPENGLPLATFORMWINDOW_H
|
||||
#define QANDROIDOPENGLPLATFORMWINDOW_H
|
||||
|
||||
#include "qeglfswindow.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QAndroidOpenGLPlatformWindow : public QEglFSWindow
|
||||
{
|
||||
public:
|
||||
QAndroidOpenGLPlatformWindow(QWindow *window);
|
||||
|
||||
QSize scheduledResize() const { return m_scheduledResize; }
|
||||
void scheduleResize(const QSize &size) { m_scheduledResize = size; }
|
||||
|
||||
void lock() { m_lock.lock(); }
|
||||
void unlock() { m_lock.unlock(); }
|
||||
|
||||
bool isExposed() const;
|
||||
|
||||
void invalidateSurface();
|
||||
void resetSurface();
|
||||
|
||||
private:
|
||||
QSize m_scheduledResize;
|
||||
QMutex m_lock;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QANDROIDOPENGLPLATFORMWINDOW_H
|
132
src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
Normal file
132
src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qeglfshooks.h"
|
||||
#include "androidjnimain.h"
|
||||
#include "qandroidplatformintegration.h"
|
||||
|
||||
#include <android/native_window.h>
|
||||
#include <jni.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QEglFSAndroidHooks: public QEglFSHooks
|
||||
{
|
||||
public:
|
||||
void platformInit();
|
||||
void platformDestroy();
|
||||
EGLNativeDisplayType platformDisplay() const;
|
||||
QSize screenSize() const;
|
||||
QSizeF physicalScreenSize() const;
|
||||
int screenDepth() const;
|
||||
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const;
|
||||
EGLNativeWindowType createNativeWindow(const QSize &size, const QSurfaceFormat &format);
|
||||
void destroyNativeWindow(EGLNativeWindowType window);
|
||||
bool hasCapability(QPlatformIntegration::Capability cap) const;
|
||||
};
|
||||
|
||||
void QEglFSAndroidHooks::platformInit()
|
||||
{
|
||||
}
|
||||
|
||||
void QEglFSAndroidHooks::platformDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
EGLNativeDisplayType QEglFSAndroidHooks::platformDisplay() const
|
||||
{
|
||||
return EGL_DEFAULT_DISPLAY;
|
||||
}
|
||||
|
||||
QSize QEglFSAndroidHooks::screenSize() const
|
||||
{
|
||||
return QtAndroid::nativeWindowSize();
|
||||
}
|
||||
|
||||
QSizeF QEglFSAndroidHooks::physicalScreenSize() const
|
||||
{
|
||||
return QSizeF(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth, QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight);
|
||||
}
|
||||
|
||||
|
||||
EGLNativeWindowType QEglFSAndroidHooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format)
|
||||
{
|
||||
ANativeWindow *window = QtAndroid::nativeWindow();
|
||||
if (window != 0)
|
||||
ANativeWindow_acquire(window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
void QEglFSAndroidHooks::destroyNativeWindow(EGLNativeWindowType window)
|
||||
{
|
||||
ANativeWindow_release(window);
|
||||
}
|
||||
|
||||
bool QEglFSAndroidHooks::hasCapability(QPlatformIntegration::Capability capability) const
|
||||
{
|
||||
switch (capability) {
|
||||
case QPlatformIntegration::OpenGL: return true;
|
||||
case QPlatformIntegration::ThreadedOpenGL: return true;
|
||||
default: return false;
|
||||
};
|
||||
}
|
||||
|
||||
int QEglFSAndroidHooks::screenDepth() const
|
||||
{
|
||||
// ### Hardcoded
|
||||
return 32;
|
||||
}
|
||||
|
||||
QSurfaceFormat QEglFSAndroidHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
|
||||
{
|
||||
QSurfaceFormat ret(inputFormat);
|
||||
ret.setAlphaBufferSize(8);
|
||||
ret.setRedBufferSize(8);
|
||||
ret.setGreenBufferSize(8);
|
||||
ret.setBlueBufferSize(8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QEglFSAndroidHooks eglFSAndroidHooks;
|
||||
QEglFSHooks *platformHooks = &eglFSAndroidHooks;
|
||||
|
||||
QT_END_NAMESPACE
|
@ -0,0 +1,288 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qandroidassetsfileenginehandler.h"
|
||||
#include "androidjnimain.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator
|
||||
{
|
||||
public:
|
||||
AndroidAbstractFileEngineIterator(QDir::Filters filters,
|
||||
const QStringList &nameFilters,
|
||||
AAssetDir *asset,
|
||||
const QString &path)
|
||||
: QAbstractFileEngineIterator(filters, nameFilters)
|
||||
{
|
||||
AAssetDir_rewind(asset);
|
||||
const char *fileName;
|
||||
while ((fileName = AAssetDir_getNextFileName(asset)))
|
||||
m_items << fileName;
|
||||
m_index = -1;
|
||||
m_path = path;
|
||||
}
|
||||
|
||||
virtual QFileInfo currentFileInfo() const
|
||||
{
|
||||
return QFileInfo(currentFilePath());
|
||||
}
|
||||
|
||||
virtual QString currentFileName() const
|
||||
{
|
||||
if (m_index < 0 || m_index >= m_items.size())
|
||||
return QString();
|
||||
return m_items[m_index];
|
||||
}
|
||||
|
||||
virtual QString currentFilePath() const
|
||||
{
|
||||
return m_path + currentFileName();
|
||||
}
|
||||
|
||||
virtual bool hasNext() const
|
||||
{
|
||||
return m_items.size() && (m_index < m_items.size() - 1);
|
||||
}
|
||||
|
||||
virtual QString next()
|
||||
{
|
||||
if (!hasNext())
|
||||
return QString();
|
||||
m_index++;
|
||||
return currentFileName();
|
||||
}
|
||||
|
||||
private:
|
||||
QString m_path;
|
||||
QStringList m_items;
|
||||
int m_index;
|
||||
};
|
||||
|
||||
class AndroidAbstractFileEngine: public QAbstractFileEngine
|
||||
{
|
||||
public:
|
||||
explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName)
|
||||
{
|
||||
m_assetDir = 0;
|
||||
m_assetFile = asset;
|
||||
m_fileName = fileName;
|
||||
}
|
||||
|
||||
explicit AndroidAbstractFileEngine(AAssetDir *asset, const QString &fileName)
|
||||
{
|
||||
m_assetFile = 0;
|
||||
m_assetDir = asset;
|
||||
m_fileName = fileName;
|
||||
if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
|
||||
m_fileName += "/";
|
||||
}
|
||||
|
||||
~AndroidAbstractFileEngine()
|
||||
{
|
||||
close();
|
||||
if (m_assetDir)
|
||||
AAssetDir_close(m_assetDir);
|
||||
}
|
||||
|
||||
virtual bool open(QIODevice::OpenMode openMode)
|
||||
{
|
||||
if (m_assetFile)
|
||||
return openMode & QIODevice::ReadOnly;
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool close()
|
||||
{
|
||||
if (m_assetFile) {
|
||||
AAsset_close(m_assetFile);
|
||||
m_assetFile = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual qint64 size() const
|
||||
{
|
||||
if (m_assetFile)
|
||||
return AAsset_getLength(m_assetFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual qint64 pos() const
|
||||
{
|
||||
if (m_assetFile)
|
||||
return AAsset_seek(m_assetFile, 0, SEEK_CUR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual bool seek(qint64 pos)
|
||||
{
|
||||
if (m_assetFile)
|
||||
return pos == AAsset_seek(m_assetFile, pos, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual qint64 read(char *data, qint64 maxlen)
|
||||
{
|
||||
if (m_assetFile)
|
||||
return AAsset_read(m_assetFile, data, maxlen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual bool isSequential() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool caseSensitive() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool isRelativePath() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual FileFlags fileFlags(FileFlags type = FileInfoAll) const
|
||||
{
|
||||
FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
|
||||
if (m_assetFile)
|
||||
flags |= FileType;
|
||||
if (m_assetDir)
|
||||
flags |= DirectoryType;
|
||||
|
||||
return type & flags;
|
||||
}
|
||||
|
||||
virtual QString fileName(FileName file = DefaultName) const
|
||||
{
|
||||
int pos;
|
||||
switch (file) {
|
||||
case DefaultName:
|
||||
case AbsoluteName:
|
||||
case CanonicalName:
|
||||
return m_fileName;
|
||||
case BaseName:
|
||||
if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
|
||||
return m_fileName.mid(pos);
|
||||
else
|
||||
return m_fileName;
|
||||
case PathName:
|
||||
case AbsolutePathName:
|
||||
case CanonicalPathName:
|
||||
if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
|
||||
return m_fileName.left(pos);
|
||||
else
|
||||
return m_fileName;
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setFileName(const QString &file)
|
||||
{
|
||||
if (file == m_fileName)
|
||||
return;
|
||||
|
||||
m_fileName = file;
|
||||
if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
|
||||
m_fileName += "/";
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
|
||||
{
|
||||
if (m_assetDir)
|
||||
return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
AAsset *m_assetFile;
|
||||
AAssetDir *m_assetDir;
|
||||
QString m_fileName;
|
||||
};
|
||||
|
||||
|
||||
AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
|
||||
{
|
||||
m_assetManager = QtAndroid::assetManager();
|
||||
}
|
||||
|
||||
AndroidAssetsFileEngineHandler::~AndroidAssetsFileEngineHandler()
|
||||
{
|
||||
}
|
||||
|
||||
QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const
|
||||
{
|
||||
if (fileName.isEmpty())
|
||||
return 0;
|
||||
|
||||
if (!fileName.startsWith(QLatin1String("assets:/")))
|
||||
return 0;
|
||||
|
||||
int prefixSize=8;
|
||||
|
||||
m_path.clear();
|
||||
if (!fileName.endsWith(QLatin1Char('/'))) {
|
||||
m_path = fileName.toUtf8();
|
||||
AAsset *asset = AAssetManager_open(m_assetManager,
|
||||
m_path.constData() + prefixSize,
|
||||
AASSET_MODE_BUFFER);
|
||||
if (asset)
|
||||
return new AndroidAbstractFileEngine(asset, fileName);
|
||||
}
|
||||
|
||||
if (!m_path.size())
|
||||
m_path = fileName.left(fileName.length() - 1).toUtf8();
|
||||
|
||||
AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, m_path.constData() + prefixSize);
|
||||
if (assetDir) {
|
||||
if (AAssetDir_getNextFileName(assetDir))
|
||||
return new AndroidAbstractFileEngine(assetDir, fileName);
|
||||
else
|
||||
AAssetDir_close(assetDir);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QANDROIDASSETSFILEENGINEHANDLER_H
|
||||
#define QANDROIDASSETSFILEENGINEHANDLER_H
|
||||
|
||||
#include <QtCore/private/qabstractfileengine_p.h>
|
||||
#include <android/asset_manager.h>
|
||||
|
||||
class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler
|
||||
{
|
||||
public:
|
||||
AndroidAssetsFileEngineHandler();
|
||||
virtual ~AndroidAssetsFileEngineHandler();
|
||||
QAbstractFileEngine *create(const QString &fileName) const;
|
||||
|
||||
private:
|
||||
AAssetManager *m_assetManager;
|
||||
mutable QByteArray m_path;
|
||||
};
|
||||
|
||||
#endif // QANDROIDASSETSFILEENGINEHANDLER_H
|
644
src/plugins/platforms/android/src/qandroidinputcontext.cpp
Normal file
644
src/plugins/platforms/android/src/qandroidinputcontext.cpp
Normal file
@ -0,0 +1,644 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include "qandroidinputcontext.h"
|
||||
#include "androidjnimain.h"
|
||||
#include "androidjniinput.h"
|
||||
#include <QDebug>
|
||||
#include <qevent.h>
|
||||
#include <qguiapplication.h>
|
||||
#include <qsharedpointer.h>
|
||||
#include <qthread.h>
|
||||
#include <qinputmethod.h>
|
||||
#include <qwindow.h>
|
||||
|
||||
#include <QTextCharFormat>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static QAndroidInputContext *m_androidInputContext = 0;
|
||||
static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection";
|
||||
static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText";
|
||||
static jclass m_extractedTextClass = 0;
|
||||
static jmethodID m_classConstructorMethodID = 0;
|
||||
static jfieldID m_partialEndOffsetFieldID = 0;
|
||||
static jfieldID m_partialStartOffsetFieldID = 0;
|
||||
static jfieldID m_selectionEndFieldID = 0;
|
||||
static jfieldID m_selectionStartFieldID = 0;
|
||||
static jfieldID m_startOffsetFieldID = 0;
|
||||
static jfieldID m_textFieldID = 0;
|
||||
|
||||
static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint newCursorPosition)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
jboolean isCopy;
|
||||
const jchar *jstr = env->GetStringChars(text, &isCopy);
|
||||
QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
|
||||
env->ReleaseStringChars(text, jstr);
|
||||
|
||||
return m_androidInputContext->commitText(str, newCursorPosition);
|
||||
}
|
||||
|
||||
static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint leftLength, jint rightLength)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->deleteSurroundingText(leftLength, rightLength);
|
||||
}
|
||||
|
||||
static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->finishComposingText();
|
||||
}
|
||||
|
||||
static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
return m_androidInputContext->getCursorCapsMode(reqModes);
|
||||
}
|
||||
|
||||
static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars, int hintMaxLines, jint flags)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QAndroidInputContext::ExtractedText &extractedText =
|
||||
m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);
|
||||
|
||||
jobject object = env->NewObject(m_extractedTextClass, m_classConstructorMethodID);
|
||||
env->SetIntField(object, m_partialStartOffsetFieldID, extractedText.partialStartOffset);
|
||||
env->SetIntField(object, m_partialEndOffsetFieldID, extractedText.partialEndOffset);
|
||||
env->SetIntField(object, m_selectionStartFieldID, extractedText.selectionStart);
|
||||
env->SetIntField(object, m_selectionEndFieldID, extractedText.selectionEnd);
|
||||
env->SetIntField(object, m_startOffsetFieldID, extractedText.startOffset);
|
||||
env->SetObjectField(object,
|
||||
m_textFieldID,
|
||||
env->NewString(reinterpret_cast<const jchar *>(extractedText.text.constData()),
|
||||
jsize(extractedText.text.length())));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QString &text = m_androidInputContext->getSelectedText(flags);
|
||||
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
|
||||
}
|
||||
|
||||
static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, jint flags)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QString &text = m_androidInputContext->getTextAfterCursor(length, flags);
|
||||
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
|
||||
}
|
||||
|
||||
static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, jint flags)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return 0;
|
||||
|
||||
const QString &text = m_androidInputContext->getTextBeforeCursor(length, flags);
|
||||
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
|
||||
}
|
||||
|
||||
static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, jint newCursorPosition)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
jboolean isCopy;
|
||||
const jchar *jstr = env->GetStringChars(text, &isCopy);
|
||||
QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
|
||||
env->ReleaseStringChars(text, jstr);
|
||||
|
||||
return m_androidInputContext->setComposingText(str, newCursorPosition);
|
||||
}
|
||||
|
||||
static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint end)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->setSelection(start, end);
|
||||
}
|
||||
|
||||
static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->selectAll();
|
||||
}
|
||||
|
||||
static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->cut();
|
||||
}
|
||||
|
||||
static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->copy();
|
||||
}
|
||||
|
||||
static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->copyURL();
|
||||
}
|
||||
|
||||
static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
|
||||
{
|
||||
if (!m_androidInputContext)
|
||||
return JNI_FALSE;
|
||||
|
||||
return m_androidInputContext->paste();
|
||||
}
|
||||
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"commitText", "(Ljava/lang/String;I)Z", (void *)commitText},
|
||||
{"deleteSurroundingText", "(II)Z", (void *)deleteSurroundingText},
|
||||
{"finishComposingText", "()Z", (void *)finishComposingText},
|
||||
{"getCursorCapsMode", "(I)I", (void *)getCursorCapsMode},
|
||||
{"getExtractedText", "(III)Lorg/qtproject/qt5/android/QtExtractedText;", (void *)getExtractedText},
|
||||
{"getSelectedText", "(I)Ljava/lang/String;", (void *)getSelectedText},
|
||||
{"getTextAfterCursor", "(II)Ljava/lang/String;", (void *)getTextAfterCursor},
|
||||
{"getTextBeforeCursor", "(II)Ljava/lang/String;", (void *)getTextBeforeCursor},
|
||||
{"setComposingText", "(Ljava/lang/String;I)Z", (void *)setComposingText},
|
||||
{"setSelection", "(II)Z", (void *)setSelection},
|
||||
{"selectAll", "()Z", (void *)selectAll},
|
||||
{"cut", "()Z", (void *)cut},
|
||||
{"copy", "()Z", (void *)copy},
|
||||
{"copyURL", "()Z", (void *)copyURL},
|
||||
{"paste", "()Z", (void *)paste}
|
||||
};
|
||||
|
||||
|
||||
QAndroidInputContext::QAndroidInputContext():QPlatformInputContext()
|
||||
{
|
||||
JNIEnv *env = 0;
|
||||
if (QtAndroid::javaVM()->AttachCurrentThread(&env, NULL) < 0) {
|
||||
qCritical() << "AttachCurrentThread failed";
|
||||
return;
|
||||
}
|
||||
|
||||
jclass clazz = QtAndroid::findClass(QtNativeInputConnectionClassName, env);
|
||||
if (clazz == NULL) {
|
||||
qCritical() << "Native registration unable to find class '"
|
||||
<< QtNativeInputConnectionClassName
|
||||
<< "'";
|
||||
return;
|
||||
}
|
||||
|
||||
if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
|
||||
qCritical() << "RegisterNatives failed for '"
|
||||
<< QtNativeInputConnectionClassName
|
||||
<< "'";
|
||||
return;
|
||||
}
|
||||
|
||||
clazz = QtAndroid::findClass(QtExtractedTextClassName, env);
|
||||
if (clazz == NULL) {
|
||||
qCritical() << "Native registration unable to find class '"
|
||||
<< QtExtractedTextClassName
|
||||
<< "'";
|
||||
return;
|
||||
}
|
||||
|
||||
m_extractedTextClass = static_cast<jclass>(env->NewGlobalRef(clazz));
|
||||
m_classConstructorMethodID = env->GetMethodID(m_extractedTextClass, "<init>", "()V");
|
||||
if (m_classConstructorMethodID == NULL) {
|
||||
qCritical() << "GetMethodID failed";
|
||||
return;
|
||||
}
|
||||
|
||||
m_partialEndOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialEndOffset", "I");
|
||||
if (m_partialEndOffsetFieldID == NULL) {
|
||||
qCritical() << "Can't find field partialEndOffset";
|
||||
return;
|
||||
}
|
||||
|
||||
m_partialStartOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialStartOffset", "I");
|
||||
if (m_partialStartOffsetFieldID == NULL) {
|
||||
qCritical() << "Can't find field partialStartOffset";
|
||||
return;
|
||||
}
|
||||
|
||||
m_selectionEndFieldID = env->GetFieldID(m_extractedTextClass, "selectionEnd", "I");
|
||||
if (m_selectionEndFieldID == NULL) {
|
||||
qCritical() << "Can't find field selectionEnd";
|
||||
return;
|
||||
}
|
||||
|
||||
m_selectionStartFieldID = env->GetFieldID(m_extractedTextClass, "selectionStart", "I");
|
||||
if (m_selectionStartFieldID == NULL) {
|
||||
qCritical() << "Can't find field selectionStart";
|
||||
return;
|
||||
}
|
||||
|
||||
m_startOffsetFieldID = env->GetFieldID(m_extractedTextClass, "startOffset", "I");
|
||||
if (m_startOffsetFieldID == NULL) {
|
||||
qCritical() << "Can't find field startOffset";
|
||||
return;
|
||||
}
|
||||
|
||||
m_textFieldID = env->GetFieldID(m_extractedTextClass, "text", "Ljava/lang/String;");
|
||||
if (m_textFieldID == NULL) {
|
||||
qCritical() << "Can't find field text";
|
||||
return;
|
||||
}
|
||||
qRegisterMetaType<QInputMethodEvent *>("QInputMethodEvent*");
|
||||
qRegisterMetaType<QInputMethodQueryEvent *>("QInputMethodQueryEvent*");
|
||||
m_androidInputContext = this;
|
||||
}
|
||||
|
||||
QAndroidInputContext::~QAndroidInputContext()
|
||||
{
|
||||
m_androidInputContext = 0;
|
||||
m_extractedTextClass = 0;
|
||||
m_partialEndOffsetFieldID = 0;
|
||||
m_partialStartOffsetFieldID = 0;
|
||||
m_selectionEndFieldID = 0;
|
||||
m_selectionStartFieldID = 0;
|
||||
m_startOffsetFieldID = 0;
|
||||
m_textFieldID = 0;
|
||||
}
|
||||
|
||||
void QAndroidInputContext::reset()
|
||||
{
|
||||
clear();
|
||||
if (qGuiApp->focusObject())
|
||||
QtAndroidInput::resetSoftwareKeyboard();
|
||||
else
|
||||
QtAndroidInput::hideSoftwareKeyboard();
|
||||
}
|
||||
|
||||
void QAndroidInputContext::commit()
|
||||
{
|
||||
finishComposingText();
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (!query.isNull()) {
|
||||
const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
|
||||
QtAndroidInput::updateSelection(cursorPos, cursorPos, -1, -1); //selection empty and no pre-edit text
|
||||
}
|
||||
}
|
||||
|
||||
void QAndroidInputContext::update(Qt::InputMethodQueries queries)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
|
||||
if (query.isNull())
|
||||
return;
|
||||
#warning TODO extract the needed data from query
|
||||
}
|
||||
|
||||
void QAndroidInputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
|
||||
{
|
||||
#warning TODO Handle at least QInputMethod::ContextMenu action
|
||||
Q_UNUSED(action)
|
||||
Q_UNUSED(cursorPosition)
|
||||
|
||||
if (action == QInputMethod::Click)
|
||||
commit();
|
||||
}
|
||||
|
||||
QRectF QAndroidInputContext::keyboardRect() const
|
||||
{
|
||||
return QPlatformInputContext::keyboardRect();
|
||||
}
|
||||
|
||||
bool QAndroidInputContext::isAnimating() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void QAndroidInputContext::showInputPanel()
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return;
|
||||
QRectF itemRect = qGuiApp->inputMethod()->inputItemRectangle();
|
||||
QRect rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(itemRect).toRect();
|
||||
QWindow *window = qGuiApp->focusWindow();
|
||||
if (window)
|
||||
rect = QRect(window->mapToGlobal(rect.topLeft()), rect.size());
|
||||
|
||||
QtAndroidInput::showSoftwareKeyboard(rect.left(),
|
||||
rect.top(),
|
||||
rect.width(),
|
||||
rect.height(),
|
||||
query->value(Qt::ImHints).toUInt());
|
||||
}
|
||||
|
||||
void QAndroidInputContext::hideInputPanel()
|
||||
{
|
||||
QtAndroidInput::hideSoftwareKeyboard();
|
||||
}
|
||||
|
||||
bool QAndroidInputContext::isInputPanelVisible() const
|
||||
{
|
||||
return QtAndroidInput::isSoftwareKeyboardVisible();
|
||||
}
|
||||
|
||||
bool QAndroidInputContext::isComposing() const
|
||||
{
|
||||
return m_composingText.length();
|
||||
}
|
||||
|
||||
void QAndroidInputContext::clear()
|
||||
{
|
||||
m_composingText.clear();
|
||||
m_extractedText.clear();
|
||||
}
|
||||
|
||||
void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodEvent *event)
|
||||
{
|
||||
QCoreApplication::sendEvent(receiver, event);
|
||||
}
|
||||
|
||||
void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodQueryEvent *event)
|
||||
{
|
||||
QCoreApplication::sendEvent(receiver, event);
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/)
|
||||
{
|
||||
m_composingText = text;
|
||||
return finishComposingText();
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return JNI_TRUE;
|
||||
|
||||
m_composingText.clear();
|
||||
|
||||
QInputMethodEvent event;
|
||||
event.setCommitString(QString(), -leftLength, leftLength+rightLength);
|
||||
sendInputMethodEvent(&event);
|
||||
clear();
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::finishComposingText()
|
||||
{
|
||||
QInputMethodEvent event;
|
||||
event.setCommitString(m_composingText);
|
||||
sendInputMethodEvent(&event);
|
||||
clear();
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
|
||||
{
|
||||
jint res = 0;
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return res;
|
||||
|
||||
const uint qtInputMethodHints = query->value(Qt::ImHints).toUInt();
|
||||
|
||||
if (qtInputMethodHints & Qt::ImhPreferUppercase)
|
||||
res = CAP_MODE_SENTENCES;
|
||||
|
||||
if (qtInputMethodHints & Qt::ImhUppercaseOnly)
|
||||
res = CAP_MODE_CHARACTERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint hintMaxChars, jint /*hintMaxLines*/, jint /*flags*/)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return m_extractedText;
|
||||
|
||||
if (hintMaxChars)
|
||||
m_extractedText.text = query->value(Qt::ImSurroundingText).toString().right(hintMaxChars);
|
||||
|
||||
m_extractedText.startOffset = query->value(Qt::ImCursorPosition).toInt();
|
||||
const QString &selection = query->value(Qt::ImCurrentSelection).toString();
|
||||
const int selLen = selection.length();
|
||||
if (selLen) {
|
||||
m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt();
|
||||
m_extractedText.selectionEnd = m_extractedText.startOffset;
|
||||
}
|
||||
|
||||
return m_extractedText;
|
||||
}
|
||||
|
||||
QString QAndroidInputContext::getSelectedText(jint /*flags*/)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return QString();
|
||||
|
||||
return query->value(Qt::ImCurrentSelection).toString();
|
||||
}
|
||||
|
||||
QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return QString();
|
||||
|
||||
QString text = query->value(Qt::ImSurroundingText).toString();
|
||||
if (!text.length())
|
||||
return text;
|
||||
|
||||
int cursorPos = query->value(Qt::ImCursorPosition).toInt();
|
||||
return text.mid(cursorPos, length);
|
||||
}
|
||||
|
||||
QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
|
||||
{
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (query.isNull())
|
||||
return QString();
|
||||
|
||||
QString text = query->value(Qt::ImSurroundingText).toString();
|
||||
if (!text.length())
|
||||
return text;
|
||||
|
||||
int cursorPos = query->value(Qt::ImCursorPosition).toInt();
|
||||
const int wordLeftPos = cursorPos - length;
|
||||
return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos);
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
|
||||
{
|
||||
if (newCursorPosition > 0)
|
||||
newCursorPosition += text.length() - 1;
|
||||
m_composingText = text;
|
||||
QList<QInputMethodEvent::Attribute> attributes;
|
||||
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
|
||||
newCursorPosition,
|
||||
1,
|
||||
QVariant()));
|
||||
// Show compose text underlined
|
||||
QTextCharFormat underlined;
|
||||
underlined.setFontUnderline(true);
|
||||
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, text.length(),
|
||||
QVariant(underlined)));
|
||||
|
||||
QInputMethodEvent event(m_composingText, attributes);
|
||||
sendInputMethodEvent(&event);
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
|
||||
if (!query.isNull()) {
|
||||
int cursorPos = query->value(Qt::ImCursorPosition).toInt();
|
||||
int preeditLength = text.length();
|
||||
QtAndroidInput::updateSelection(cursorPos+preeditLength, cursorPos+preeditLength, cursorPos, cursorPos+preeditLength);
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::setSelection(jint start, jint end)
|
||||
{
|
||||
QList<QInputMethodEvent::Attribute> attributes;
|
||||
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
|
||||
start,
|
||||
end - start,
|
||||
QVariant()));
|
||||
|
||||
QInputMethodEvent event(QString(), attributes);
|
||||
sendInputMethodEvent(&event);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::selectAll()
|
||||
{
|
||||
#warning TODO
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::cut()
|
||||
{
|
||||
#warning TODO
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::copy()
|
||||
{
|
||||
#warning TODO
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::copyURL()
|
||||
{
|
||||
#warning TODO
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
jboolean QAndroidInputContext::paste()
|
||||
{
|
||||
#warning TODO
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries)
|
||||
{
|
||||
#warning TODO make qGuiApp->focusObject() thread safe !!!
|
||||
QObject *focusObject = qGuiApp->focusObject();
|
||||
if (!focusObject)
|
||||
return QSharedPointer<QInputMethodQueryEvent>();
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> ret = QSharedPointer<QInputMethodQueryEvent>(new QInputMethodQueryEvent(queries));
|
||||
if (qGuiApp->thread()==QThread::currentThread()) {
|
||||
QCoreApplication::sendEvent(focusObject, ret.data());
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this,
|
||||
"sendEvent",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QObject*, focusObject),
|
||||
Q_ARG(QInputMethodQueryEvent*, ret.data()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void QAndroidInputContext::sendInputMethodEvent(QInputMethodEvent *event)
|
||||
{
|
||||
#warning TODO make qGuiApp->focusObject() thread safe !!!
|
||||
QObject *focusObject = qGuiApp->focusObject();
|
||||
if (!focusObject)
|
||||
return;
|
||||
|
||||
if (qGuiApp->thread() == QThread::currentThread()) {
|
||||
QCoreApplication::sendEvent(focusObject, event);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this,
|
||||
"sendEvent",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QObject*, focusObject),
|
||||
Q_ARG(QInputMethodEvent*, event));
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
130
src/plugins/platforms/android/src/qandroidinputcontext.h
Normal file
130
src/plugins/platforms/android/src/qandroidinputcontext.h
Normal file
@ -0,0 +1,130 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ANDROIDINPUTCONTEXT_H
|
||||
#define ANDROIDINPUTCONTEXT_H
|
||||
|
||||
#include <qpa/qplatforminputcontext.h>
|
||||
#include <jni.h>
|
||||
#include <qevent.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QAndroidInputContext: public QPlatformInputContext
|
||||
{
|
||||
Q_OBJECT
|
||||
enum CapsMode
|
||||
{
|
||||
CAP_MODE_CHARACTERS = 0x00001000,
|
||||
CAP_MODE_SENTENCES = 0x00004000,
|
||||
CAP_MODE_WORDS = 0x00002000
|
||||
};
|
||||
|
||||
public:
|
||||
struct ExtractedText
|
||||
{
|
||||
ExtractedText() { clear(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
partialEndOffset = partialStartOffset = selectionEnd = selectionStart = startOffset = -1;
|
||||
text.clear();
|
||||
}
|
||||
|
||||
int partialEndOffset;
|
||||
int partialStartOffset;
|
||||
int selectionEnd;
|
||||
int selectionStart;
|
||||
int startOffset;
|
||||
QString text;
|
||||
};
|
||||
|
||||
public:
|
||||
QAndroidInputContext();
|
||||
~QAndroidInputContext();
|
||||
bool isValid() const { return true; }
|
||||
|
||||
void reset();
|
||||
void commit();
|
||||
void update(Qt::InputMethodQueries queries);
|
||||
void invokeAction(QInputMethod::Action action, int cursorPosition);
|
||||
QRectF keyboardRect() const;
|
||||
bool isAnimating() const;
|
||||
void showInputPanel();
|
||||
void hideInputPanel();
|
||||
bool isInputPanelVisible() const;
|
||||
|
||||
bool isComposing() const;
|
||||
void clear();
|
||||
|
||||
//---------------//
|
||||
jboolean commitText(const QString &text, jint newCursorPosition);
|
||||
jboolean deleteSurroundingText(jint leftLength, jint rightLength);
|
||||
jboolean finishComposingText();
|
||||
jint getCursorCapsMode(jint reqModes);
|
||||
const ExtractedText &getExtractedText(jint hintMaxChars, jint hintMaxLines, jint flags);
|
||||
QString getSelectedText(jint flags);
|
||||
QString getTextAfterCursor(jint length, jint flags);
|
||||
QString getTextBeforeCursor(jint length, jint flags);
|
||||
jboolean setComposingText(const QString &text, jint newCursorPosition);
|
||||
jboolean setSelection(jint start, jint end);
|
||||
jboolean selectAll();
|
||||
jboolean cut();
|
||||
jboolean copy();
|
||||
jboolean copyURL();
|
||||
jboolean paste();
|
||||
|
||||
private:
|
||||
QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
|
||||
void sendInputMethodEvent(QInputMethodEvent *event);
|
||||
|
||||
private slots:
|
||||
virtual void sendEvent(QObject *receiver, QInputMethodEvent *event);
|
||||
virtual void sendEvent(QObject *receiver, QInputMethodQueryEvent *event);
|
||||
|
||||
private:
|
||||
ExtractedText m_extractedText;
|
||||
QString m_composingText;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // ANDROIDINPUTCONTEXT_H
|
@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qandroidplatformclipboard.h"
|
||||
#include "androidjniclipboard.h"
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
#include <QMimeData>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QAndroidPlatformClipboard::QAndroidPlatformClipboard()
|
||||
{
|
||||
QtAndroidClipboard::setClipboardListener(this);
|
||||
}
|
||||
|
||||
QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode)
|
||||
{
|
||||
if (QClipboard::Clipboard != mode || !QtAndroidClipboard::hasClipboardText())
|
||||
return 0;
|
||||
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
mimeData->setText(QtAndroidClipboard::clipboardText());
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
|
||||
{
|
||||
if (!data || !data->hasText() || QClipboard::Clipboard != mode)
|
||||
return;
|
||||
|
||||
QtAndroidClipboard::setClipboardText(data->text());
|
||||
}
|
||||
|
||||
bool QAndroidPlatformClipboard::supportsMode(QClipboard::Mode mode) const
|
||||
{
|
||||
return QClipboard::Clipboard == mode;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_CLIPBOARD
|
@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QANDROIDPLATFORMCLIPBOARD_H
|
||||
#define QANDROIDPLATFORMCLIPBOARD_H
|
||||
|
||||
#include <qpa/qplatformclipboard.h>
|
||||
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QAndroidPlatformClipboard: public QPlatformClipboard
|
||||
{
|
||||
public:
|
||||
QAndroidPlatformClipboard();
|
||||
|
||||
virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
|
||||
virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
|
||||
virtual bool supportsMode(QClipboard::Mode mode) const;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
#endif // QT_NO_CLIPBOARD
|
||||
|
||||
#endif // QANDROIDPLATFORMCLIPBOARD_H
|
@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins 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 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.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include "qandroidplatformfontdatabase.h"
|
||||
|
||||
QString QAndroidPlatformFontDatabase::fontDir() const
|
||||
{
|
||||
return QLatin1String("/system/fonts");
|
||||
}
|
||||
|
||||
void QAndroidPlatformFontDatabase::populateFontDatabase()
|
||||
{
|
||||
QString fontpath = fontDir();
|
||||
|
||||
if (!QFile::exists(fontpath)) {
|
||||
qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
|
||||
qPrintable(fontpath));
|
||||
}
|
||||
|
||||
QDir dir(fontpath, QLatin1String("*.ttf"));
|
||||
for (int i = 0; i < int(dir.count()); ++i) {
|
||||
const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
|
||||
addTTFile(QByteArray(), file);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &family,
|
||||
QFont::Style style,
|
||||
QFont::StyleHint styleHint,
|
||||
QChar::Script script) const
|
||||
{
|
||||
Q_UNUSED(family);
|
||||
Q_UNUSED(style);
|
||||
Q_UNUSED(script);
|
||||
if (styleHint == QFont::Monospace)
|
||||
return QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";");
|
||||
|
||||
return QString(qgetenv("QT_ANDROID_FONTS")).split(";");
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user