--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org )t
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Compile program for the Android platform
+module android_platform
+
+import platform
+import abstract_compiler
+
+redef class ToolContext
+ redef fun platform_from_name(name)
+ do
+ if name == "android" then return new AndroidPlatform
+ return super
+ end
+
+ fun exec_and_check(args: Array[String])
+ do
+ var prog = args.first
+ args.remove_at 0
+
+ # Is the wanted program available?
+ var proc_which = new IProcess.from_a("which", [prog])
+ proc_which.wait
+ var res = proc_which.status
+ if res != 0 then
+ print "Android project error: executable \"{prog}\" not found"
+ exit 1
+ end
+
+ # Execute the wanted program
+ var proc = new Process.from_a(prog, args)
+ proc.wait
+ res = proc.status
+ if res != 0 then
+ print "Android project error: execution of \"{prog} {args.join(" ")}\" failed"
+ exit 1
+ end
+ end
+end
+
+class AndroidPlatform
+ super Platform
+
+ redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext)
+end
+
+class AndroidToolchain
+ super MakefileToolchain
+
+ var android_project_root: String
+
+ redef fun compile_dir
+ do
+ var normal_compile_dir = super
+ android_project_root = normal_compile_dir
+ return "{normal_compile_dir}/jni/"
+ end
+
+ redef fun write_files(compiler, compile_dir, cfiles)
+ do
+ var app_name = compiler.mainmodule.name
+ var app_package = "org.nitlanguage.{app_name}"
+ var app_version = "0.1"
+
+ var args = ["android", "-s", "create", "project", "--name", app_name,
+ "--target", "android-10", "--path", android_project_root,
+ "--package", app_package, "--activity", app_name]
+ toolcontext.exec_and_check(args)
+
+ # create compile_dir
+ var dir = "{android_project_root}/jni/"
+ if not dir.file_exists then dir.mkdir
+
+ # compile normal C files
+ super(compiler, compile_dir, cfiles)
+
+ # Gather extra C files generated elsewhere than in super
+ for f in compiler.extern_bodies do
+ if f isa ExternCFile then cfiles.add(f.filename.basename(""))
+ end
+
+ ### generate makefile into "{compile_dir}/Android.mk"
+ if not dir.file_exists then dir.mkdir
+ var file = new OFStream.open("{dir}/Android.mk")
+ file.write """
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -D ANDROID
+LOCAL_MODULE := main
+LOCAL_SRC_FILES := \\
+{{{cfiles.join(" \\\n")}}}
+LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM -lz
+LOCAL_STATIC_LIBRARIES := android_native_app_glue
+
+include $(BUILD_SHARED_LIBRARY)
+
+$(call import-module,android/native_app_glue)
+"""
+ file.close
+
+ ### generate AndroidManifest.xml
+ dir = android_project_root
+ file = new OFStream.open("{dir}/AndroidManifest.xml")
+ file.write """<?xml version="1.0" encoding="utf-8"?>
+<!-- BEGIN_INCLUDE(manifest) -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="{{{app_package}}}"
+ android:versionCode="1"
+ android:versionName="{{{app_version}}}"
+ android:debuggable="true">
+
+ <!-- This is the platform API where NativeActivity was introduced. -->
+ <uses-sdk android:minSdkVersion="9" />
+
+ <!-- This .apk has no Java code itself, so set hasCode to false. -->
+ <application android:label="@string/app_name" android:hasCode="false" android:debuggable="true">
+
+ <!-- Our activity is the built-in NativeActivity framework class.
+ This will take care of integrating with our NDK code. -->
+ <activity android:name="android.app.NativeActivity"
+ android:label="@string/app_name"
+ android:configChanges="orientation|keyboardHidden">
+ <!-- Tell NativeActivity the name of or .so -->
+ <meta-data android:name=\"{{{app_package}}}\"
+ android:value=\"{{{app_name}}}\" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+<!-- END_INCLUDE(manifest) -->
+"""
+ file.close
+
+ ### generate res/values/strings.xml
+ dir = "{android_project_root}/res/"
+ if not dir.file_exists then dir.mkdir
+ dir = "{dir}/values/"
+ if not dir.file_exists then dir.mkdir
+ file = new OFStream.open("{dir}/strings.xml")
+ file.write """<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">{{{app_name}}}</string>
+</resources>"""
+ file.close
+ end
+
+ redef fun write_makefile(compiler, compile_dir, cfiles)
+ do
+ # Do nothing, already done in `write_files`
+ end
+
+ redef fun compile_c_code(compiler, compile_dir)
+ do
+ # Compile C code (and thus Nit)
+ toolcontext.exec_and_check(["ndk-build", "-s", "-j", "4", "-C", android_project_root])
+
+ # Generate the apk
+ toolcontext.exec_and_check(["ant", "-q", "debug", "-f", android_project_root+"/build.xml"])
+ end
+end