diff --git a/.cirrus.yml b/.cirrus.yml index 829e865fec57e..3a855bb2720e5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -176,3 +176,11 @@ task: CI_USE_APT_INSTALL: "no" PACKAGE_MANAGER_INSTALL: "echo" # Nothing to do FILE_ENV: "./ci/test/00_setup_env_mac_host.sh" + +task: + name: 'ARM64 Android APK [bionic]' + << : *GLOBAL_TASK_TEMPLATE + container: + image: ubuntu:bionic + env: + FILE_ENV: "./ci/test/00_setup_env_android.sh" diff --git a/ci/test/00_setup_env_android.sh b/ci/test/00_setup_env_android.sh new file mode 100644 index 0000000000000..42a244546749c --- /dev/null +++ b/ci/test/00_setup_env_android.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2019-2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +export CONTAINER_NAME=ci_android +export PACKAGES="clang llvm unzip openjdk-8-jdk gradle" + +export ANDROID_API_LEVEL=28 +export ANDROID_BUILD_TOOLS_VERSION=28.0.3 +export ANDROID_NDK_VERSION=21.1.6352462 +export ANDROID_TOOLS_URL=https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip + +export SYSCOIN_CONFIG="--disable-ccache" \ No newline at end of file diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh index 017e590eda5eb..f95496e372a4d 100755 --- a/ci/test/05_before_script.sh +++ b/ci/test/05_before_script.sh @@ -22,6 +22,20 @@ if [ -n "$XCODE_VERSION" ] && [ ! -f "$OSX_SDK_PATH" ]; then DOCKER_EXEC curl --location --fail "${SDK_URL}/${OSX_SDK_BASENAME}" -o "$OSX_SDK_PATH" fi +if [ -n "$ANDROID_TOOLS_URL" ]; then + ANDROID_TOOLS_PATH=$DEPENDS_DIR/sdk-sources/android-tools.zip + ANDROID_HOME="$DEPENDS_DIR"/SDKs/android + ANDROID_NDK_HOME=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION} + + DOCKER_EXEC curl --location --fail "${ANDROID_TOOLS_URL}" -o "$ANDROID_TOOLS_PATH" + DOCKER_EXEC mkdir -p "${ANDROID_HOME}/cmdline-tools" + DOCKER_EXEC unzip -o "$ANDROID_TOOLS_PATH" -d "${ANDROID_HOME}/cmdline-tools" + DOCKER_EXEC "yes | ${ANDROID_HOME}/cmdline-tools/tools/bin/sdkmanager --install \"build-tools;${ANDROID_BUILD_TOOLS_VERSION}\" \"platform-tools\" \"platforms;android-${ANDROID_API_LEVEL}\" \"ndk;${ANDROID_NDK_VERSION}\"" + + MAKE_COMMAND="ANDROID_SDK=${ANDROID_HOME} ANDROID_NDK=${ANDROID_NDK_HOME} make $MAKEJOBS -C depends HOST=aarch64-linux-android ANDROID_API_LEVEL=${ANDROID_API_LEVEL} ANDROID_TOOLCHAIN_BIN=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/toolchains/llvm/prebuilt/linux-x86_64/bin/ $DEP_OPTS" + DOCKER_EXEC "$MAKE_COMMAND" HOST=aarch64-linux-android +fi + if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then # Use BDB compiled using install_db4.sh script to work around linking issue when using BDB # from depends. See https://github.com/bitcoin/bitcoin/pull/18288#discussion_r433189350 for diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh index 03b907ac1d62c..756ac41adfd5c 100755 --- a/ci/test/06_script_a.sh +++ b/ci/test/06_script_a.sh @@ -6,6 +6,14 @@ export LC_ALL=C.UTF-8 +if [ -n "$ANDROID_TOOLS_URL" ]; then + DOCKER_EXEC make distclean || true + DOCKER_EXEC ./autogen.sh + DOCKER_EXEC ./configure $SYSCOIN_CONFIG --prefix=$DEPENDS_DIR/aarch64-linux-android || ( (DOCKER_EXEC cat config.log) && false) + DOCKER_EXEC "cd src/qt && make $MAKEJOBS && ANDROID_HOME=${ANDROID_HOME} ANDROID_NDK_HOME=${ANDROID_NDK_HOME} make apk" + exit 0 +fi + SYSCOIN_CONFIG_ALL="--enable-suppress-external-warnings --disable-dependency-tracking --prefix=$DEPENDS_DIR/$HOST --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib" if [ -z "$NO_WERROR" ]; then SYSCOIN_CONFIG_ALL="${SYSCOIN_CONFIG_ALL} --enable-werror" diff --git a/configure.ac b/configure.ac index 4840874bd9260..b801b33f317b7 100644 --- a/configure.ac +++ b/configure.ac @@ -734,6 +734,21 @@ case $host in *android*) dnl make sure android stays above linux for hosts like *linux-android* TARGET_OS=android + case $host in + *x86_64*) + ANDROID_ARCH=x86_64 + ;; + *aarch64*) + ANDROID_ARCH=arm64-v8a + ;; + *armv7a*) + ANDROID_ARCH=armeabi-v7a + ;; + *i686*) + ANDROID_ARCH=i686 + ;; + *) AC_MSG_ERROR("Could not determine Android arch") ;; + esac ;; *linux*) TARGET_OS=linux @@ -1874,6 +1889,7 @@ AC_SUBST(HAVE_BUILTIN_PREFETCH) AC_SUBST(HAVE_MM_PREFETCH) AC_SUBST(HAVE_STRONG_GETAUXVAL) AC_SUBST(HAVE_WEAK_GETAUXVAL) +AC_SUBST(ANDROID_ARCH) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])]) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 5d576945da404..1a6758fa548f2 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -9,7 +9,7 @@ $(package)_qt_libs=corelib network widgets gui plugins testlib $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch $(package)_patches+= fix_android_qmake_conf.patch fix_android_jni_static.patch dont_hardcode_pwd.patch $(package)_patches+= drop_lrelease_dependency.patch no_sdk_version_check.patch -$(package)_patches+= fix_qpainter_non_determinism.patch fix_lib_paths.patch +$(package)_patches+= fix_qpainter_non_determinism.patch fix_lib_paths.patch fix_android_pch.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=e1de58ed108b7e0a138815ea60fd46a2c4e1fc31396a707e5630e92de79c53de @@ -165,6 +165,7 @@ $(package)_config_opts_android += -no-fontconfig $(package)_config_opts_android += -L $(host_prefix)/lib $(package)_config_opts_android += -I $(host_prefix)/include $(package)_config_opts_android += -pch +$(package)_config_opts_android += -no-feature-vulkan $(package)_config_opts_aarch64_android += -android-arch arm64-v8a $(package)_config_opts_armv7a_android += -android-arch armeabi-v7a @@ -224,6 +225,7 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_android_qmake_conf.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_android_pch.patch && \ patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_qpainter_non_determinism.patch &&\ patch -p1 -i $($(package)_patch_dir)/no_sdk_version_check.patch && \ diff --git a/depends/patches/qt/fix_android_pch.patch b/depends/patches/qt/fix_android_pch.patch new file mode 100644 index 0000000000000..bed6e4bb63597 --- /dev/null +++ b/depends/patches/qt/fix_android_pch.patch @@ -0,0 +1,10 @@ +--- old/qtbase/mkspecs/common/android-base-head.conf ++++ new/qtbase/mkspecs/common/android-base-head.conf +@@ -73,6 +73,6 @@ CROSS_COMPILE = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX- + QMAKE_PCH_OUTPUT_EXT = .gch + + QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} +-QMAKE_CFLAGS_USE_PRECOMPILE = -include ${QMAKE_PCH_OUTPUT_BASE} ++QMAKE_CFLAGS_USE_PRECOMPILE = -include-pch ${QMAKE_PCH_OUTPUT} + QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} + QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE diff --git a/doc/README.md b/doc/README.md index 05d079e278225..1390f7027fbb5 100644 --- a/doc/README.md +++ b/doc/README.md @@ -44,6 +44,7 @@ The following are developer notes on how to build Syscoin Core on your native pl - [FreeBSD Build Notes](build-freebsd.md) - [OpenBSD Build Notes](build-openbsd.md) - [NetBSD Build Notes](build-netbsd.md) +- [Android Build Notes](build-android.md) - [Gitian Building Guide (External Link)](https://github.com/bitcoin-core/docs/blob/master/gitian-building.md) Development diff --git a/doc/build-android.md b/doc/build-android.md new file mode 100644 index 0000000000000..3f4b3b9f14b8d --- /dev/null +++ b/doc/build-android.md @@ -0,0 +1,12 @@ +ANDROID BUILD NOTES +====================== + +This guide describes how to build and package the `syscoin-qt` GUI for Android on Linux and macOS. + +## Preparation + +You will need to get the Android NDK and build dependencies for Android as described in [depends/README.md](../depends/README.md). + +## Building and packaging + +After the depends are built configure with one of the resulting prefixes and run `make && make apk` in `src/qt`. \ No newline at end of file diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index f3639e01cb6e7..87a6e9ba612ac 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -383,6 +383,20 @@ syscoin_qt_clean: FORCE syscoin_qt : qt/syscoin-qt$(EXEEXT) +APK_LIB_DIR = qt/android/libs/$(ANDROID_ARCH) +QT_BASE_PATH = $(shell find ../depends/sources/ -maxdepth 1 -type f -regex ".*qtbase.*\.tar.xz") +QT_BASE_TLD = $(shell tar tf $(QT_BASE_PATH) --exclude='*/*') + +syscoin_qt_apk: FORCE + mkdir -p $(APK_LIB_DIR) + cp $(dir $(CC))../sysroot/usr/lib/$(host_alias)/libc++_shared.so $(APK_LIB_DIR) + tar xf $(QT_BASE_PATH) -C qt/android/src/ $(QT_BASE_TLD)src/android/jar/src --strip-components=5 + tar xf $(QT_BASE_PATH) -C qt/android/src/ $(QT_BASE_TLD)src/android/java/src --strip-components=5 + tar xf $(QT_BASE_PATH) -C qt/android/res/ $(QT_BASE_TLD)src/android/java/res --strip-components=5 + cp qt/syscoin-qt $(APK_LIB_DIR)/libsyscoin-qt.so + cd qt/android && gradle wrapper --gradle-version=6.6.1 + cd qt/android && ./gradlew build + ui_%.h: %.ui @test -f $(UIC) @$(MKDIR_P) $(@D) diff --git a/src/qt/Makefile b/src/qt/Makefile index 60dfa8b966eb4..1ecb8d57250e0 100644 --- a/src/qt/Makefile +++ b/src/qt/Makefile @@ -7,3 +7,5 @@ check: FORCE $(MAKE) -C .. test_syscoin_qt_check syscoin-qt syscoin-qt.exe: FORCE $(MAKE) -C .. syscoin_qt +apk: FORCE + $(MAKE) -C .. syscoin_qt_apk diff --git a/src/qt/android/AndroidManifest.xml b/src/qt/android/AndroidManifest.xml new file mode 100644 index 0000000000000..a45f92dc3d998 --- /dev/null +++ b/src/qt/android/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/android/build.gradle b/src/qt/android/build.gradle new file mode 100644 index 0000000000000..4c36e79db8fb4 --- /dev/null +++ b/src/qt/android/build.gradle @@ -0,0 +1,52 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.1.0' + } +} + +repositories { + google() + jcenter() +} + +apply plugin: 'com.android.application' + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) +} + +android { + compileSdkVersion androidCompileSdkVersion.toInteger() + + buildToolsVersion androidBuildToolsVersion + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] + aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] + res.srcDirs = [qt5AndroidDir + '/res', 'res'] + resources.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } + + lintOptions { + abortOnError false + } + + dexOptions { + javaMaxHeapSize '4g' + } + + defaultConfig { + minSdkVersion 24 + } +} diff --git a/src/qt/android/gradle.properties b/src/qt/android/gradle.properties new file mode 100644 index 0000000000000..838870f62d81b --- /dev/null +++ b/src/qt/android/gradle.properties @@ -0,0 +1,4 @@ +androidBuildToolsVersion=28.0.3 +androidCompileSdkVersion=28 +qt5AndroidDir=new File(".").absolutePath +org.gradle.jvmargs=-Xmx4608M diff --git a/src/qt/android/res/drawable-hdpi/syscoin.png b/src/qt/android/res/drawable-hdpi/syscoin.png new file mode 100644 index 0000000000000..ddf0351e55668 Binary files /dev/null and b/src/qt/android/res/drawable-hdpi/syscoin.png differ diff --git a/src/qt/android/res/drawable-ldpi/syscoin.png b/src/qt/android/res/drawable-ldpi/syscoin.png new file mode 100644 index 0000000000000..33f8218821f9b Binary files /dev/null and b/src/qt/android/res/drawable-ldpi/syscoin.png differ diff --git a/src/qt/android/res/drawable-mdpi/syscoin.png b/src/qt/android/res/drawable-mdpi/syscoin.png new file mode 100644 index 0000000000000..b339269f20c09 Binary files /dev/null and b/src/qt/android/res/drawable-mdpi/syscoin.png differ diff --git a/src/qt/android/res/drawable-xhdpi/syscoin.png b/src/qt/android/res/drawable-xhdpi/syscoin.png new file mode 100644 index 0000000000000..c8dc4f43174a3 Binary files /dev/null and b/src/qt/android/res/drawable-xhdpi/syscoin.png differ diff --git a/src/qt/android/res/drawable-xxhdpi/syscoin.png b/src/qt/android/res/drawable-xxhdpi/syscoin.png new file mode 100644 index 0000000000000..1d913a2786585 Binary files /dev/null and b/src/qt/android/res/drawable-xxhdpi/syscoin.png differ diff --git a/src/qt/android/res/drawable-xxxhdpi/syscoin.png b/src/qt/android/res/drawable-xxxhdpi/syscoin.png new file mode 100644 index 0000000000000..0aa6800163bad Binary files /dev/null and b/src/qt/android/res/drawable-xxxhdpi/syscoin.png differ diff --git a/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java b/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java new file mode 100644 index 0000000000000..b0589881bd875 --- /dev/null +++ b/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java @@ -0,0 +1,29 @@ +package org.syscoincore.qt; + +import android.os.Bundle; +import android.system.ErrnoException; +import android.system.Os; + +import org.qtproject.qt5.android.bindings.QtActivity; + +import java.io.File; + +public class SyscoinQtActivity extends QtActivity +{ + @Override + public void onCreate(Bundle savedInstanceState) + { + final File syscoinDir = new File(getFilesDir().getAbsolutePath() + "/.syscoin"); + if (!syscoinDir.exists()) { + syscoinDir.mkdir(); + } + + try { + Os.setenv("QT_QPA_PLATFORM", "android", true); + } catch (ErrnoException e) { + e.printStackTrace(); + } + + super.onCreate(savedInstanceState); + } +} diff --git a/src/qt/syscoin.cpp b/src/qt/syscoin.cpp index db2290bde9095..32f12ece3afdf 100644 --- a/src/qt/syscoin.cpp +++ b/src/qt/syscoin.cpp @@ -492,6 +492,12 @@ int GuiMain(int argc, char* argv[]) QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#if defined(QT_QPA_PLATFORM_ANDROID) + QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar); + QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); + QApplication::setAttribute(Qt::AA_DontUseNativeDialogs); +#endif + SyscoinApplication app; QFontDatabase::addApplicationFont(":/fonts/monospace");