/* * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * Gets the most recent android platform installed, relative to the given path. * The path will either be ANDROID_SDK or ANDROID_NDK * TODO Shouldn't we instead just ask people to point to the one they want to use? * * @param path The path to the Android SDK or NDK * @return The name of the most recent platform */ String getLatestPlatform(String path) { def max = 0 file(cygpath("$path/platforms")).eachFile() {file-> def pname = file.getName() - "android-" def ptf = pname?.isInteger() ? pname.toInteger() : 0 if (max < ptf) { max = ptf } } if (max == 0) { return null; } return "android-" + max } int compareVersions(String s1, String s2) { def v1t = s1.tokenize(".") def v2t = s2.tokenize(".") for(int i = 0; i < v1t.size(); i++) { if (i == v2t.size()) { return 1 } int n1 = v1t[i].isInteger() ? v1t[i].toInteger() : 0 int n2 = v2t[i].isInteger() ? v2t[i].toInteger() : 0 if (n1 == n2) { continue } else if (n1 > n2) { return 1; } else { return -1 } } return (v2t.size() > v1t.size()) ? -1 : 0 } String getLatestToolchain(String ndk, String tch) { def max = "0.0" def matchFile = null file(cygpath("$ndk/toolchains")).eachFile() {file-> def filename = file.getName() if (filename.startsWith(tch)) { def p = filename - "$tch-" if (compareVersions(p, max) > 0) { max = p matchFile = file } } } return matchFile.getAbsolutePath() } boolean assertDir(File dir) { return dir != null && dir.exists() && dir.isDirectory() && dir.canRead(); } boolean assertDir(String dir) { return assertDir(file(dir)) } def closedDir = file("$projectDir/../rt-closed") def toolchainArchs = ["arm-linux-androideabi", "mipsel-linux-android", "x86"] def armArchs = ["armeabi", "armeabiv-7a"] ANDROID = [:] ANDROID.compileSwing = false; ANDROID.compileSWT = false; ANDROID.glassPlatform = "android" ANDROID.armArch = armArchs[0] ANDROID.libDest = "lib" ANDROID.jfxdvklib = "jfxdvk.jar" ANDROID.library = { name -> return "lib${name}.so" as String } def sdk = project.hasProperty("ANDROID_SDK") ? "${ANDROID_SDK}" : null; def ndk = project.hasProperty("ANDROID_NDK") ? "${ANDROID_NDK}" : null; ANDROID.canBuild = sdk != null && ndk != null if (!ANDROID.canBuild) { fail("Can't build Android. Path to SDK or NDK was not set or is invalid!") } ANDROID.canBuild = assertDir(sdk) && assertDir(ndk) if (!ANDROID.canBuild) { if (!assertDir(sdk)) { logger.error("Path to ANDROID_SDK is invalid! [$sdk]") } if (!assertDir(ndk)) { logger.error("Path to ANDROID_NDK is invalid! [$ndk]") } fail("Cannot build, missing android tools") } def sdk_target = project.hasProperty("ANDROID_SDK_TARGET") ? "${ANDROID_SDK_TARGET}" : getLatestPlatform(sdk); if (!assertDir(file("$sdk/platforms/$sdk_target"))) { sdk_target = getLatestPlatform(sdk); logger.warn("Redefine ANDROID_SDK_TARGET to: [$sdk_target]") } def ndk_target = project.hasProperty("ANDROID_NDK_TARGET") ? "${ANDROID_NDK_TARGET}" : getLatestPlatform(ndk); if (!assertDir(file("$ndk/platforms/$ndk_target"))) { ndk_target = getLatestPlatform(ndk); logger.warn("Redefine ANDROID_NDK_TARGET to: [$ndk_target]") } ANDROID.canBuild = sdk_target != null && ndk_target != null if (!ANDROID.canBuild) { fail("Can't determine sdk or ndk target platform!") } def toolchainHome = project.hasProperty("ANDROID_CROSS_TOOLS_VER") ? "$ndk/toolchains/${ANDROID_CROSS_TOOLS_VER}" : getLatestToolchain(ndk, toolchainArchs[0]) if (!assertDir(toolchainHome)) { toolchainHome = getLatestToolchain(ndk, toolchainArchs[0]) logger.warn("Redefine toolchain to [$toolchainHome]") } // Look for the the Android SDK & NDK to use, as well as the compiler stuff def compilerHome = null file("$toolchainHome/prebuilt").eachDir() {subdir -> compilerHome = subdir.getAbsolutePath() return } ANDROID.canBuild = compilerHome != null if (!ANDROID.canBuild) { fail("Failed to access toolchain [$toolchainHome/prebuilt/$toolsPlatform]!") } def freetypeDir = project.hasProperty("FREETYPE_DIR") ? "${FREETYPE_DIR}" : null if (!assertDir(freetypeDir)) { logger.warn("FREETYPE_DIR $freetypeDir doesn't exists! Build continues without native text support.") freetypeDir = null } def compileNativeText = freetypeDir != null def compiler = file("$compilerHome/bin/${toolchainArchs[0]}-gcc").getAbsolutePath() def linker = file("$compilerHome/bin/${toolchainArchs[0]}-g++").getAbsolutePath() // Log the settings we're building with logger.quiet("ANDROID_SDK: $sdk") logger.quiet("ANDROID_SDK_TARGET: $sdk_target") logger.quiet("ANDROID_NDK: $ndk") logger.quiet("ANDROID_NDK_TARGET: $ndk_target") logger.quiet("FREETYPE_DIR: $freetypeDir") logger.quiet("Compile native text: $compileNativeText") logger.quiet("Android Compiler: $compiler") logger.quiet("Android Linker: $linker") project(":graphics") { task compileDalvikLibs(type: JavaCompile, group: "Build") { description = "Task compiles dalvik vm based libraries." sourceCompatibility = JavaVersion.VERSION_1_6 targetCompatibility = JavaVersion.VERSION_1_6 options.bootClasspath = "$sdk/platforms/$sdk_target/android.jar" classpath = files("build/classes/android") destinationDir = file("build/classes/android") dependencyCacheDir = file("build/dependency-cache") source fileTree(dir: 'src/android/java').matching { include 'com/oracle/dalvik/**' } } task jarDalvikLibs(type: Jar, group: "Build", dependsOn: compileDalvikLibs) { description = "Creates jfxdvk.jar with all dalvik based classes." archiveName = "jfxdvk.jar" includeEmptyDirs = false from("build/classes/android") include("com/oracle/dalvik/**/*") dependsOn(compileDalvikLibs) } afterEvaluate { addNative(project, "surface", ["android"]) addNative(project, "vmlauncher", ["android"]) if (compileNativeText) { addNative(project, "fontNativeFreetype", ["android"]) } tasks["javahAndroidVmlauncher"].dependsOn(compileDalvikLibs) tasks["native"].dependsOn("nativeSurface", "nativeVmlauncher") if (compileNativeText) { tasks["native"].dependsOn("nativeFontNativeFreetype") } sdkAndroid { dependsOn(jarDalvikLibs) doLast { def props = project.ext["ANDROID"] copy { from( "${project("graphics").buildDir}/libs/vmlauncher/android/${props.library(props.vmlauncher.lib)}", "${project("graphics").buildDir}/libs/surface/android/${props.library(props.surface.lib)}" ) into ("build/android-sdk/dalvik/${props.libDest}") } copy { from ("${project("graphics").buildDir}/libs/${props.jfxdvklib}") into ("build/android-sdk/dalvik/lib") } if (compileNativeText) { copy { from ("${project("graphics").buildDir}/libs/fontNativeFreetype/android") into ("build/android-sdk/$ANDROID.libDest") } } } } } } project(":controls") { afterEvaluate { task compileControlsJavaAndroid(type: JavaCompile, group: "Build", dependsOn: [":graphics:compileJava", ":controls:compileJava"]) { description = "Task compiles controls for Android" classpath = files("${project("base").buildDir}/classes/main", "${project("graphics").buildDir}/classes/main", "${project("controls").buildDir}/classes/main" ) destinationDir = file("${project("controls").buildDir}/classes/android") dependencyCacheDir = file("${project("controls").buildDir}/dependency-cache") source file("${project("controls").projectDir}/src/android/java") } task processControlsResourcesAndroid() { copy { from ("${project("controls").projectDir}/src/android/resources") into ("${project("controls").buildDir}/resources/android") } } sdkAndroid { dependsOn(compileControlsJavaAndroid, processControlsResourcesAndroid) } } } project(":web") { apply plugin: 'java' compileJava { enabled = false } afterEvaluate { if (!BUILD_CLOSED) { logger.warn("OpenJFX build. Skipping webkit build on Android.") return } def compileWebJavaAndroid = task("compileWebJavaAndroid", type: JavaCompile, group: "Build") { dependsOn(project(":graphics").classes, project(":base").classes) description = "Task compiles web component for Android." classpath = files( project(":controls").sourceSets.main.java.outputDir, project(":graphics").sourceSets.main.java.outputDir, project(":base").sourceSets.main.java.outputDir ) destinationDir = file("${project("web").buildDir}/classes/android") dependencyCacheDir = file("${project("web").buildDir}/dependency-cache") source file("${project("web").projectDir}/src/android/java") } def jarWebJavaAndroid = task("jarWebJavaAndroid", type: Jar, group: "Build") { description = "Creates web.jar for Android." dependsOn(compileWebJavaAndroid) archiveName = "web.jar" includeEmptyDirs = false destinationDir = project.file("build/libs/android") from("build/classes/android") } addNative(project, "webview", ["android"]) addNative(project, "dvkwebview", ["android"]) javahAndroidWebview.dependsOn(compileWebJavaAndroid) javahAndroidDvkwebview.dependsOn(compileWebJavaAndroid) jfxrtAndroid { from "${project("web").buildDir}/classes/android" } sdkAndroid { dependsOn(jarWebJavaAndroid) doLast { def props = project.ext["ANDROID"] copy { from( "${project("web").buildDir}/libs/dvkwebview/android/${props.library(props.dvkwebview.lib)}" ) into ("build/android-sdk/dalvik/${props.libDest}") } copy { from ("${project("web").buildDir}/libs/webview/android/${props.library(props.webview.lib)}") into ("build/android-sdk/${props.libDest}") } } } } } ANDROID.jfxrtJarExcludes = [ "**/*.hlsl", "com/sun/glass/ui/win", "com/sun/prism/d3d", "com/sun/prism/es2/gl/win", "com/sun/prism/null3d", "com/sun/scenario/effect/impl/hw/d3d", "com/sun/glass/events/mac", "com/sun/glass/ui/mac", "com/sun/prism/es2/gl/mac", "com/sun/glass/ui/gtk", "com/sun/glass/ui/ios", "com/sun/prism/es2/gl/eglx11", "com/sun/prism/es2/gl/x11", "com/sun/glass/ui/swt", // SWT glass "javafx/embed/swing", // Swing Interop "javafx/embed/swt", // SWT Interop "com/oracle/dalvik" ] def text = (compileNativeText) ? "native" : "" ANDROID.javafxPlatformProperties = """ javafx.platform=android android.glass.platform=Lens android.glass.lens=eglfb android.prism.glDepthSize=16 android.prism.lcdtext=false android.prism.debugfonts=true android.prism.text=$text android.embedded=eglfb android.prism.allowhidpi=false android.prism.maxTextureSize=2048 android.prism.dirtyopts=true android.prism.vsync=false android.log.lens=FINE android.use.egl=true android.com.sun.javafx.isEmbedded=true """ def sysroot = "$ndk/platforms/$ndk_target/arch-arm" def ccFlags = ["--sysroot=$sysroot","-std=c99", "-DANDROID", "-c", "-nostdlib", "-DANDROID_NDK"] if (project.hasProperty("DALVIK_VM")) { ccFlags += ["-DDALVIK_VM"] } def ccOptFlags = ["-fpic", "-ffunction-sections", "-funwind-tables","-fstack-protector", "-Os", "-O2", "-fno-strict-aliasing", "-finline-limit=64", "-fomit-frame-pointer"] def ccWarnFlags = ["-Wa,--noexecstack", "-Wno-psabi"] def ccArchFlags = ["-mthumb", "-msoft-float", "-D__ARM_ARCH_5__", "-D__ARM_ARCH_5T__", "-D__ARM_ARCH_5E__", "-D__ARM_ARCH_5TE__", "-march=armv5te" , "-mtune=xscale"] def ccDebugFlags = [IS_DEBUG_NATIVE ? "-DDEBUG" : "-DNDEBUG"] def ccDefaultIncludeFlags = ["-I$ndk/platforms/$ndk_target/arch-arm/usr/include"] def linkFlags = ["--sysroot=$sysroot", "-Wl,--no-undefined", "-Wl,-z,noexecstack", "-lc", "-lm", "-shared", "-L$ndk/platforms/$ndk_target/arch-arm/usr/lib"] ANDROID.vmlauncher = [:] ANDROID.vmlauncher.classpath = files("$sdk/platforms/$sdk_target/android.jar", "${project("graphics").buildDir}/classes/android") ANDROID.vmlauncher.javahSource = files("${project("graphics").buildDir}/classes/android") ANDROID.vmlauncher.javahClasspath = files("${project("graphics").buildDir}/classes/android", "$sdk/platforms/$sdk_target/android.jar") ANDROID.vmlauncher.javahInclude = [ "com/oracle/dalvik/*" ] ANDROID.vmlauncher.nativeSource = [ file("${project("graphics").projectDir}/src/android/native/VMLauncher.c"), file("${project("graphics").projectDir}/src/android/native/NativePipeReader.c"), file("${project("graphics").projectDir}/src/android/native/DalvikProxySelector.c") ] ANDROID.vmlauncher.compiler = compiler ANDROID.vmlauncher.linker = linker ANDROID.vmlauncher.lib = "vmlauncher" ANDROID.vmlauncher.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.vmlauncher.linkFlags = [linkFlags, "-llog"].flatten() ANDROID.surface = [:] ANDROID.surface.javahInclude = [ "com/sun/glass/events/*", "com/sun/glass/ui/android/*" ] ANDROID.surface.nativeSource = [ file("${project("graphics").projectDir}/src/main/native-glass/lens/android") ] ANDROID.surface.compiler = compiler ANDROID.surface.linker = linker ANDROID.surface.lib = "glass_lens_android" ANDROID.surface.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags, "-Isrc/main/native-glass/lens"].flatten() ANDROID.surface.linkFlags = [linkFlags, "-ldl", "-landroid", "-llog"].flatten() ANDROID.webview = [:] ANDROID.webview.javahSource = files("${project("web").buildDir}/classes/android") ANDROID.webview.javahClasspath = files("${project("web").buildDir}/classes/android") ANDROID.webview.javahInclude = [ "com/sun/webkit/NativeWebView.class" ] ANDROID.webview.nativeSource = [ file("${project("web").projectDir}/src/android/native/native_webview.c") ] ANDROID.webview.compiler = compiler ANDROID.webview.linker = linker ANDROID.webview.lib = "webview" ANDROID.webview.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.webview.linkFlags = [linkFlags, "-ldl", "-llog"].flatten() ANDROID.dvkwebview = [:] ANDROID.dvkwebview.javahSource = files("${project("web").buildDir}/classes/android") ANDROID.dvkwebview.javahClasspath = files("${project("web").buildDir}/classes/android") ANDROID.dvkwebview.javahInclude = [ "com/sun/webkit/NativeWebView.class" ] ANDROID.dvkwebview.nativeSource = [ file("${project("web").projectDir}/src/android/native/android_webview.c") ] ANDROID.dvkwebview.compiler = compiler ANDROID.dvkwebview.linker = linker ANDROID.dvkwebview.lib = "android_webview" ANDROID.dvkwebview.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.dvkwebview.linkFlags = [linkFlags, "-ldl", "-llog"].flatten() ANDROID.glass = [:] ANDROID.glass.variants = ["eglfb", "lensport"] ANDROID.glass.javahInclude = [ "com/sun/glass/events/**", "com/sun/glass/ui/*", "com/sun/glass/ui/android/*", "com/sun/glass/ui/lens/*"] ANDROID.glass.lensport = [:] ANDROID.glass.lensport.nativeSource = [ file("${project("graphics").projectDir}/src/main/native-glass/lens/lensport"), file("${project("graphics").projectDir}/src/main/native-glass/lens/lensport/initPlatform.c"), file("${project("graphics").projectDir}/src/main/native-glass/lens/lensport/wrapped_functions.c") ] ANDROID.glass.lensport.compiler = compiler ANDROID.glass.lensport.linker = linker ANDROID.glass.lensport.lib = "lens_porting" ANDROID.glass.lensport.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags, "-DISEGLFB", "-DLENSPORT", "-I", file("${project("graphics").projectDir}/src/main/native-glass/lens")].flatten() ANDROID.glass.lensport.linkFlags = [linkFlags, "-ldl", "-llog"].flatten() ANDROID.glass.eglfb = [:] ANDROID.glass.eglfb.nativeSource = [ file("${project("graphics").projectDir}/src/main/native-glass/lens"), file("${project("graphics").projectDir}/src/main/native-glass/lens/wm"), file("${project("graphics").projectDir}/src/main/native-glass/lens/cursor/nullCursor"), file("${project("graphics").projectDir}/src/main/native-glass/lens/input/android"), file("${project("graphics").projectDir}/src/main/native-glass/lens/wm/screen/androidScreen.c") ] ANDROID.glass.eglfb.compiler = compiler ANDROID.glass.eglfb.linker = linker ANDROID.glass.eglfb.lib = "glass_lens_eglfb" ANDROID.glass.eglfb.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.glass.eglfb.linkFlags = [linkFlags, "-ldl", "-landroid", "-llog"].flatten() ANDROID.prism = [:] ANDROID.prism.javahInclude = ["com/sun/prism/impl/**/*", "com/sun/prism/PresentableState*"] ANDROID.prism.nativeSource = file("${project("graphics").projectDir}/src/main/native-prism") ANDROID.prism.compiler = compiler ANDROID.prism.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.prism.linker = linker ANDROID.prism.linkFlags = [linkFlags].flatten() ANDROID.prism.lib = "prism_common" ANDROID.prismSW = [:] ANDROID.prismSW.javahInclude = ["com/sun/pisces/**/*"] ANDROID.prismSW.nativeSource = file("${project("graphics").projectDir}/src/main/native-prism-sw") ANDROID.prismSW.compiler = compiler ANDROID.prismSW.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.prismSW.linker = linker ANDROID.prismSW.linkFlags = [linkFlags].flatten() ANDROID.prismSW.lib = "prism_sw" ANDROID.decora = [:] ANDROID.decora.compiler = compiler ANDROID.decora.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.decora.linker = linker ANDROID.decora.linkFlags = [linkFlags].flatten() ANDROID.decora.lib = "decora_sse" ANDROID.iio = [:] ANDROID.iio.javahInclude = ["com/sun/javafx/iio/**/*"] ANDROID.iio.nativeSource = [ file("${project("graphics").projectDir}/src/main/native-iio"), file("${project("graphics").projectDir}/src/main/native-iio/libjpeg9c")] ANDROID.iio.compiler = compiler ANDROID.iio.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.iio.linker = linker ANDROID.iio.linkFlags = [linkFlags].flatten() ANDROID.iio.lib = "javafx_iio" ANDROID.prismES2 = [:] ANDROID.prismES2.variants = ["eglfb"] ANDROID.prismES2.javahInclude = ["com/sun/prism/es2/**/*"] ANDROID.prismES2.eglfb = [:] ANDROID.prismES2.eglfb.nativeSource = [ file("${project("graphics").projectDir}/src/main/native-prism-es2"), file("${project("graphics").projectDir}/src/main/native-prism-es2/GL"), file("${project("graphics").projectDir}/src/main/native-prism-es2/eglfb")] ANDROID.prismES2.eglfb.compiler = compiler ANDROID.prismES2.eglfb.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags, "-DIS_EGLFB"].flatten() ANDROID.prismES2.eglfb.linker = linker ANDROID.prismES2.eglfb.linkFlags = [linkFlags, "-ldl", "-llog", "-lGLESv2", "-lEGL"].flatten() ANDROID.prismES2.eglfb.lib = "prism_es2_eglfb" ANDROID.font = [:] ANDROID.font.javahInclude = [ "com/sun/javafx/font/**/*", "com/sun/javafx/text/**/*"] ANDROID.font.nativeSource = [file("$closedDir/javafx-font-native/src")] ANDROID.font.compiler = compiler ANDROID.font.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten() ANDROID.font.linker = linker ANDROID.font.linkFlags = [linkFlags].flatten() ANDROID.font.lib = "javafx_font" if (compileNativeText) { ANDROID.fontNativeFreetype = [:] ANDROID.fontNativeFreetype.javahInclude = [ "com/sun/javafx/font/freetype/OSFreetype.class" ] ANDROID.fontNativeFreetype.nativeSource = [ file("${project("graphics").projectDir}/src/main/native-font/freetype.c") ] ANDROID.fontNativeFreetype.compiler = compiler ANDROID.fontNativeFreetype.linker = linker ANDROID.fontNativeFreetype.lib = "javafx_font_freetype" ccFlags += ["-D_ENABLE_HARFBUZZ"] ANDROID.fontNativeFreetype.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags, "-I$freetypeDir/include", "-I$freetypeDir/include/freetype2"].flatten() ANDROID.fontNativeFreetype.linkFlags = [linkFlags, "-llog", "-L$freetypeDir/lib", "$freetypeDir/lib/libfreetype.a"].flatten() } ANDROID.media = [:] ANDROID.media.compiler = compiler ANDROID.media.linker = linker ANDROID.media.lib = file("$compilerHome/bin/${toolchainArchs[0]}-ar").getAbsolutePath()