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:
Paul Olav Tvete 2013-03-04 10:16:42 +01:00 committed by The Qt Project
parent 1b582d64eb
commit 97fcf3bc98
137 changed files with 13917 additions and 107 deletions

View File

@ -40,6 +40,7 @@
****************************************************************************/ ****************************************************************************/
#include <linux/fb.h> #include <linux/fb.h>
#include <sys/kd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
int main(int, char **) int main(int, char **)

View File

@ -36,6 +36,8 @@ if [ -f ./arch.exe ]; then
binary=./arch.exe binary=./arch.exe
elif [ -f ./arch ]; then elif [ -f ./arch ]; then
binary=./arch binary=./arch
elif [ -f ./libarch.so ]; then
binary=./libarch.so
else else
[ "$VERBOSE" = "yes" ] && echo "Unable to determine architecture!" [ "$VERBOSE" = "yes" ] && echo "Unable to determine architecture!"
exit 2 exit 2

View File

@ -67,7 +67,7 @@ test -r Makefile && $MAKE distclean >/dev/null 2>&1
# Make sure output from possible previous tests is gone # Make sure output from possible previous tests is gone
rm -f "$EXE" "${EXE}.exe" 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 if [ "$VERBOSE" = "yes" ]; then
OUTDIR=$OUTDIR "$@" OUTDIR=$OUTDIR "$@"
$MAKE $MAKE

172
configure vendored
View File

@ -875,6 +875,7 @@ RPATH_FLAGS=
W_FLAGS= W_FLAGS=
QCONFIG_FLAGS= QCONFIG_FLAGS=
XPLATFORM= # This seems to be the QMAKESPEC, like "linux-g++" XPLATFORM= # This seems to be the QMAKESPEC, like "linux-g++"
XPLATFORM_ANDROID=no
XPLATFORM_MINGW=no # Whether target platform is MinGW (win32-g++*) XPLATFORM_MINGW=no # Whether target platform is MinGW (win32-g++*)
XPLATFORM_MAEMO=no XPLATFORM_MAEMO=no
XPLATFORM_QNX=no XPLATFORM_QNX=no
@ -955,6 +956,15 @@ CFG_SQL_oci=no
CFG_SQL_db2=no CFG_SQL_db2=no
CFG_SQL_AVAILABLE= 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 if [ -d "$relpath/src/plugins/sqldrivers" ]; then
for a in "$relpath/src/plugins/sqldrivers/"*; do for a in "$relpath/src/plugins/sqldrivers/"*; do
if [ -d "$a" ]; then if [ -d "$a" ]; then
@ -1016,7 +1026,7 @@ while [ "$#" -gt 0 ]; do
VAL=no VAL=no
;; ;;
#Qt style options that pass an argument #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,"` VAR=`echo $1 | sed "s,^-\(.*\),\1,"`
shift shift
VAL="$1" VAL="$1"
@ -2148,6 +2158,24 @@ while [ "$#" -gt 0 ]; do
UNKNOWN_OPT=yes UNKNOWN_OPT=yes
fi 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 UNKNOWN_OPT=yes
;; ;;
@ -2520,9 +2548,89 @@ fi
[ -z "$XPLATFORM" ] && XPLATFORM="$PLATFORM" [ -z "$XPLATFORM" ] && XPLATFORM="$PLATFORM"
case `basename "$XPLATFORM"` in win32-g++*) XPLATFORM_MINGW=yes;; esac case `basename "$XPLATFORM"` in win32-g++*) XPLATFORM_MINGW=yes;; esac
case "$XPLATFORM" in *-maemo*) XPLATFORM_MAEMO=yes;; esac case "$XPLATFORM" in
case "$XPLATFORM" in *qnx-*|*blackberry-*) XPLATFORM_QNX=yes;; esac *-maemo*)
case "$XPLATFORM" in *ios*) XPLATFORM_IOS=yes;; esac 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 if [ -d "$PLATFORM" ]; then
QMAKESPEC="$PLATFORM" QMAKESPEC="$PLATFORM"
@ -2644,6 +2752,32 @@ fi
QMAKE_CONF_COMPILER=`getXQMakeConf QMAKE_CXX` QMAKE_CONF_COMPILER=`getXQMakeConf QMAKE_CXX`
TEST_COMPILER=$QMAKE_CONF_COMPILER 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 [ "$XPLATFORM_SYMBIAN_SBSV2" = "no" ]; then
if [ -z "$TEST_COMPILER" ]; then if [ -z "$TEST_COMPILER" ]; then
echo "ERROR: Cannot set the compiler for the configuration tests" echo "ERROR: Cannot set the compiler for the configuration tests"
@ -3354,6 +3488,31 @@ Qt/Mac only:
QT_ENABLE_HARFBUZZ environment variable. QT_ENABLE_HARFBUZZ environment variable.
EOF 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 fi
[ "x$ERROR" = "xyes" ] && exit 1 [ "x$ERROR" = "xyes" ] && exit 1
@ -4079,6 +4238,7 @@ elif [ "$CFG_ARCH" != "mips" ]; then
fi fi
[ "$XPLATFORM_MINGW" = "yes" ] && QMakeVar add styles "windowsxp windowsvista" [ "$XPLATFORM_MINGW" = "yes" ] && QMakeVar add styles "windowsxp windowsvista"
[ "$XPLATFORM_ANDROID" = "yes" ] && QMakeVar add styles "android"
# detect zlib # detect zlib
if [ "$CFG_ZLIB" = "no" ]; then if [ "$CFG_ZLIB" = "no" ]; then
@ -5088,7 +5248,7 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then
fi fi
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 [ "$CFG_XCB" = "no" ] && [ "$CFG_EGLFS" = "no" ] && [ "$CFG_DIRECTFB" = "no" ] && [ "$CFG_LINUXFB" = "no" ] && [ "$CFG_KMS" = "no" ]; then
if [ "$QPA_PLATFORM_GUARD" = "yes" ] && 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 ( [ "$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 CFG_OPENSSL=yes
fi fi
else 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 "OpenSSL support cannot be enabled due to functionality tests!"
echo " Turn on verbose messaging (-v) to $0 to see the final report." 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" echo " If you believe this message is in error you may use the continue"

View 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)

View 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

View 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
View 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

View File

@ -2,7 +2,7 @@ CONFIG += qpa/basicunixfontdatabase
contains(QT_CONFIG, fontconfig) { contains(QT_CONFIG, fontconfig) {
DEFINES += Q_FONTCONFIGDATABASE DEFINES += Q_FONTCONFIGDATABASE
LIBS += -lfontconfig LIBS += -lfontconfig
} else { } else:!android {
fonts.path = $$[QT_INSTALL_LIBS]/fonts fonts.path = $$[QT_INSTALL_LIBS]/fonts
fonts.files = $$QT_SOURCE_TREE/lib/fonts/* fonts.files = $$QT_SOURCE_TREE/lib/fonts/*
INSTALLS += fonts INSTALLS += fonts

View 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
}

View File

@ -107,6 +107,8 @@ aix-g++* {
QMAKE_CXXFLAGS += -mminimal-toc QMAKE_CXXFLAGS += -mminimal-toc
} }
android: CONFIG += qt_android_deps
#install directives #install directives
load(qt_installs) load(qt_installs)

View File

@ -174,7 +174,7 @@ QMAKE_LIBS_OPENGL =
QMAKE_LIBS_OPENGL_ES1 = -lGLESv1_CM QMAKE_LIBS_OPENGL_ES1 = -lGLESv1_CM
QMAKE_LIBS_OPENGL_ES2 = -lEGL -lGLESv2 $$QMAKE_LIBS 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) load(qt_config)
QT_CONFIG -=accessibility QT_CONFIG -=accessibility

View File

@ -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)

View File

@ -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)

View File

@ -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
View 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

View 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>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">QtJar</string>
</resources>

View File

@ -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();
}
}

View File

@ -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);
// }
}

View File

@ -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);
}
}

View 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));
}
}

View 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
}

View File

@ -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;
}
}

View 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;
}
}

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}
}

View 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>

View File

@ -89,7 +89,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include <locale.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> # include <langinfo.h>
#endif #endif

View File

@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_TEXTCODEC #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 #define QT_LOCALE_IS_UTF8
#endif #endif

View File

@ -16,6 +16,12 @@ win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x
QMAKE_DOCS = $$PWD/doc/qtcore.qdocconf 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) load(qt_module)
include(animation/animation.pri) include(animation/animation.pri)

View File

@ -57,6 +57,10 @@
#include <slog2.h> #include <slog2.h>
#endif #endif
#ifdef Q_OS_ANDROID
#include <android/log.h>
#endif
#include <stdio.h> #include <stdio.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -835,6 +839,24 @@ Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
static QtMsgHandler msgHandler = 0; // pointer to debug handler (without context) static QtMsgHandler msgHandler = 0; // pointer to debug handler (without context)
static QtMessageHandler messageHandler = 0; // pointer to debug handler (with 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 \internal
*/ */
@ -855,6 +877,8 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con
#if defined(QT_USE_SLOG2) #if defined(QT_USE_SLOG2)
slog2_default_handler(type, logMessage.toLocal8Bit().constData()); slog2_default_handler(type, logMessage.toLocal8Bit().constData());
#elif defined(Q_OS_ANDROID)
android_default_message_handler(type, context, logMessage);
#else #else
fprintf(stderr, "%s", logMessage.toLocal8Bit().constData()); fprintf(stderr, "%s", logMessage.toLocal8Bit().constData());
fflush(stderr); fflush(stderr);

View File

@ -80,6 +80,7 @@
LYNX - LynxOS LYNX - LynxOS
BSD4 - Any BSD 4.4 system BSD4 - Any BSD 4.4 system
UNIX - Any UNIX BSD/SYSV system UNIX - Any UNIX BSD/SYSV system
ANDROID - Android platform
*/ */
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__)) #if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
@ -90,6 +91,9 @@
# else # else
# define Q_OS_DARWIN32 # define Q_OS_DARWIN32
# endif # endif
#elif defined(ANDROID)
# define Q_OS_ANDROID
# define Q_OS_LINUX
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
# define Q_OS_CYGWIN # define Q_OS_CYGWIN
#elif !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) #elif !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))

View File

@ -133,7 +133,7 @@ win32 {
SOURCES += io/qstandardpaths_unix.cpp SOURCES += io/qstandardpaths_unix.cpp
} }
linux-*|if(qnx:contains(QT_CONFIG, inotify)) { linux|if(qnx:contains(QT_CONFIG, inotify)) {
SOURCES += io/qfilesystemwatcher_inotify.cpp SOURCES += io/qfilesystemwatcher_inotify.cpp
HEADERS += io/qfilesystemwatcher_inotify_p.h HEADERS += io/qfilesystemwatcher_inotify_p.h
} }

View File

@ -169,7 +169,7 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
if (entry.isEmpty() || entry.isRoot()) if (entry.isEmpty() || entry.isRoot())
return entry; 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 // realpath(X,0) is not supported
Q_UNUSED(data); Q_UNUSED(data);
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath())); return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));

View File

@ -52,7 +52,7 @@
#endif #endif
#include <stdlib.h> // mkdtemp #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> #include <private/qfilesystemengine_p.h>
#endif #endif
@ -94,9 +94,9 @@ static QString defaultTemplateName()
return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX"); return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX");
} }
#if defined(Q_OS_QNX ) || defined(Q_OS_WIN) static char *q_mkdtemp(char *templateName)
static char *mkdtemp(char *templateName)
{ {
#if defined(Q_OS_QNX ) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const size_t length = strlen(templateName); const size_t length = strlen(templateName);
@ -137,17 +137,17 @@ static char *mkdtemp(char *templateName)
} }
} }
return 0; return 0;
} #else
#elif defined(Q_OS_LINUX_ANDROID) return mkdtemp(templateName);
extern char *mkdtemp(char *);
#endif #endif
}
void QTemporaryDirPrivate::create(const QString &templateName) void QTemporaryDirPrivate::create(const QString &templateName)
{ {
QByteArray buffer = QFile::encodeName(templateName); QByteArray buffer = QFile::encodeName(templateName);
if (!buffer.endsWith("XXXXXX")) if (!buffer.endsWith("XXXXXX"))
buffer += "XXXXXX"; buffer += "XXXXXX";
if (mkdtemp(buffer.data())) { // modifies buffer if (q_mkdtemp(buffer.data())) { // modifies buffer
success = true; success = true;
path = QFile::decodeName(buffer.constData()); path = QFile::decodeName(buffer.constData());
} }

View File

@ -129,7 +129,7 @@ unix|integrity {
contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) 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 \ SOURCES += kernel/qsharedmemory_unix.cpp \
kernel/qsystemsemaphore_unix.cpp kernel/qsystemsemaphore_unix.cpp
} else { } else {

View File

@ -69,7 +69,7 @@ namespace QSharedMemoryPrivate
#include "qsystemsemaphore.h" #include "qsystemsemaphore.h"
#include "private/qobject_p.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> # include <sys/sem.h>
#endif #endif

View File

@ -287,7 +287,7 @@ static void setCurrentThreadName(pthread_t threadId, const char *name)
void *QThreadPrivate::start(void *arg) void *QThreadPrivate::start(void *arg)
{ {
#if !defined(Q_OS_LINUX_ANDROID) #if !defined(Q_OS_ANDROID)
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
#endif #endif
pthread_cleanup_push(QThreadPrivate::finish, arg); pthread_cleanup_push(QThreadPrivate::finish, arg);
@ -326,7 +326,7 @@ void *QThreadPrivate::start(void *arg)
#endif #endif
emit thr->started(QThread::QPrivateSignal()); emit thr->started(QThread::QPrivateSignal());
#if !defined(Q_OS_LINUX_ANDROID) #if !defined(Q_OS_ANDROID)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel(); pthread_testcancel();
#endif #endif
@ -631,7 +631,7 @@ void QThread::start(Priority priority)
void QThread::terminate() void QThread::terminate()
{ {
#if !defined(Q_OS_LINUX_ANDROID) #if !defined(Q_OS_ANDROID)
Q_D(QThread); Q_D(QThread);
QMutexLocker locker(&d->mutex); QMutexLocker locker(&d->mutex);
@ -673,7 +673,7 @@ void QThread::setTerminationEnabled(bool enabled)
"Current thread was not started with QThread."); "Current thread was not started with QThread.");
Q_UNUSED(thr) Q_UNUSED(thr)
#if defined(Q_OS_LINUX_ANDROID) #if defined(Q_OS_ANDROID)
Q_UNUSED(enabled); Q_UNUSED(enabled);
#else #else
pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL); pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);

View File

@ -49,7 +49,7 @@
#include <string> #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 // std::wstring is disabled on android's glibc, as bionic lacks certain features
// that libstdc++ checks for (like mbcslen). // that libstdc++ checks for (like mbcslen).
namespace std namespace std

View File

@ -1507,10 +1507,20 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
{ {
QWindow *window = e->window.data(); QWindow *window = e->window.data();
modifier_buttons = e->modifiers; 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(); window = QGuiApplication::focusWindow();
if (!window) }
if (!window
#ifdef Q_OS_ANDROID
&& e->keyType != QEvent::KeyRelease && e->key != Qt::Key_Back
#endif
) {
return; return;
}
if (window->d_func()->blockedByModalWindow) { if (window->d_func()->blockedByModalWindow) {
// a modal window is blocking this window, don't allow key events through // a modal window is blocking this window, don't allow key events through
return; return;
@ -1520,7 +1530,19 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers,
e->unicode, e->repeat, e->repeatCount); e->unicode, e->repeat, e->repeatCount);
ev.setTimestamp(e->timestamp); 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) void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e)

View File

@ -65,7 +65,11 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op,
} }
QUrl url = request.url(); 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; return new QNetworkAccessFileBackend;
} else if (!url.scheme().isEmpty() && url.authority().isEmpty() && (url.scheme().length() > 1)) { } 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 // check if QFile could, in theory, open this URL via the file engines
@ -113,10 +117,16 @@ void QNetworkAccessFileBackend::open()
QString fileName = url.toLocalFile(); QString fileName = url.toLocalFile();
if (fileName.isEmpty()) { if (fileName.isEmpty()) {
if (url.scheme() == QLatin1String("qrc")) if (url.scheme() == QLatin1String("qrc")) {
fileName = QLatin1Char(':') + url.path(); fileName = QLatin1Char(':') + url.path();
else } else {
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery); #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); file.setFileName(fileName);

View File

@ -1010,7 +1010,11 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
// fast path for GET on file:// URLs // fast path for GET on file:// URLs
// The QNetworkAccessFileBackend will right now only be used for PUT // The QNetworkAccessFileBackend will right now only be used for PUT
if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation) 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); return new QNetworkReplyFileImpl(this, req, op);
} }

View File

@ -91,10 +91,16 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ
QString fileName = url.toLocalFile(); QString fileName = url.toLocalFile();
if (fileName.isEmpty()) { if (fileName.isEmpty()) {
if (url.scheme() == QLatin1String("qrc")) if (url.scheme() == QLatin1String("qrc")) {
fileName = QLatin1Char(':') + url.path(); fileName = QLatin1Char(':') + url.path();
else } else {
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery); #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); QFileInfo fi(fileName);

View File

@ -27,7 +27,7 @@ SOURCES += kernel/qauthenticator.cpp \
unix:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.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_unix.cpp
SOURCES += kernel/qdnslookup_android.cpp SOURCES += kernel/qdnslookup_android.cpp
} }

View File

@ -323,7 +323,7 @@ QString QHostInfo::localHostName()
QString QHostInfo::localDomainName() QString QHostInfo::localDomainName()
{ {
#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_LINUX_ANDROID) #if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)
resolveLibrary(); resolveLibrary();
if (local_res_ninit) { if (local_res_ninit) {
// using thread-safe version // using thread-safe version

View File

@ -61,7 +61,7 @@
# define QT_NO_GETIFADDRS # define QT_NO_GETIFADDRS
#endif #endif
#ifdef Q_OS_LINUX_ANDROID #ifdef Q_OS_ANDROID
// android lacks if_nameindex // android lacks if_nameindex
# define QT_NO_IPV6IFNAME # define QT_NO_IPV6IFNAME
#endif #endif

View File

@ -681,10 +681,19 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
} }
#elif defined(Q_OS_UNIX) #elif defined(Q_OS_UNIX)
QSet<QString> certFiles; QSet<QString> certFiles;
# ifdef Q_OS_ANDROID
QList<QByteArray> directories;
directories << qgetenv("MINISTRO_SSL_CERTS_PATH"); // Set by Ministro
# else
QList<QByteArray> directories = unixRootCertDirectories(); QList<QByteArray> directories = unixRootCertDirectories();
# endif
QDir currentDir; QDir currentDir;
QStringList nameFilters; QStringList nameFilters;
# ifdef Q_OS_ANDROID
nameFilters << QLatin1String("*.der");
#else
nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt"); nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
# endif
currentDir.setNameFilters(nameFilters); currentDir.setNameFilters(nameFilters);
for (int a = 0; a < directories.count(); a++) { for (int a = 0; a < directories.count(); a++) {
currentDir.setPath(QLatin1String(directories.at(a))); currentDir.setPath(QLatin1String(directories.at(a)));
@ -697,10 +706,16 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
} }
QSetIterator<QString> it(certFiles); QSetIterator<QString> it(certFiles);
while(it.hasNext()) { 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("/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 systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/share/certs/ca-root-nss.crt"), QSsl::Pem)); // FreeBSD's ca_root_nss
# endif
#endif #endif
#ifdef QSSLSOCKET_DEBUG #ifdef QSSLSOCKET_DEBUG
qDebug() << "systemCaCertificates retrieval time " << timer.elapsed() << "ms"; qDebug() << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";

View File

@ -8,6 +8,9 @@ irix-cc*:QMAKE_CXXFLAGS += -no_prelink -ptused
QMAKE_DOCS = $$PWD/doc/qtopengl.qdocconf QMAKE_DOCS = $$PWD/doc/qtopengl.qdocconf
ANDROID_LIB_DEPENDENCY_REPLACEMENTS = \
"plugins/platforms/android/libqtforandroid.so:plugins/platforms/android/libqtforandroidGL.so"
load(qt_module) load(qt_module)
contains(QT_CONFIG, opengl):CONFIG += opengl contains(QT_CONFIG, opengl):CONFIG += opengl

View File

@ -1,4 +1,4 @@
linux-*:contains(QT_CONFIG, evdev) { linux:contains(QT_CONFIG, evdev) {
HEADERS += $$PWD/qdevicediscovery_p.h HEADERS += $$PWD/qdevicediscovery_p.h
contains(QT_CONFIG, libudev) { contains(QT_CONFIG, libudev) {

View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS += raster opengl

View 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)

View 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)

View File

@ -0,0 +1,3 @@
{
"Keys": [ "android" ]
}

View 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;
}
}

View 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

View 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;
}
}

View 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

View 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;
}

View 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

View 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;
}
}

View 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

View 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 &paramList);
};
QPlatformIntegration *QAndroidPlatformIntegrationPlugin::create(const QString &key, const QStringList &paramList)
{
Q_UNUSED(paramList);
if (key.toLower() == "android")
return new QAndroidPlatformIntegration(paramList);
return 0;
}
QT_END_NAMESPACE
#include "androidplatformplugin.moc"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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;
}

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -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