- android application
authorEvrim Ulu <evrimulu@gmail.com>
Wed, 25 Mar 2015 20:06:53 +0000 (22:06 +0200)
committerEvrim Ulu <evrimulu@gmail.com>
Wed, 25 Mar 2015 20:06:53 +0000 (22:06 +0200)
- android application README
- ECL android README.android
 added.

26 files changed:
README.android [new file with mode: 0644]
contrib/android/.classpath [new file with mode: 0644]
contrib/android/.project [new file with mode: 0644]
contrib/android/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
contrib/android/AndroidManifest.xml [new file with mode: 0644]
contrib/android/README [new file with mode: 0644]
contrib/android/ant.properties [new file with mode: 0644]
contrib/android/assets/lisp/help.doc [new file with mode: 0644]
contrib/android/assets/lisp/init.lisp [new file with mode: 0644]
contrib/android/assets/lisp/slime [new submodule]
contrib/android/assets/lisp/user.lisp [new file with mode: 0644]
contrib/android/build.xml [new file with mode: 0644]
contrib/android/jni/Android.mk [new file with mode: 0644]
contrib/android/jni/ecl_boot.c [new file with mode: 0644]
contrib/android/jni/ecl_boot.h [new file with mode: 0644]
contrib/android/jni/org_lisp_ecl_EmbeddedCommonLisp.c [new file with mode: 0644]
contrib/android/jni/org_lisp_ecl_EmbeddedCommonLisp.h [new file with mode: 0644]
contrib/android/local.properties [new file with mode: 0644]
contrib/android/obj/local/armeabi/libhello-ecl.so [new file with mode: 0755]
contrib/android/proguard-project.txt [new file with mode: 0644]
contrib/android/project.properties [new file with mode: 0644]
contrib/android/res/layout/main.xml [new file with mode: 0644]
contrib/android/res/layout/menu.xml [new file with mode: 0644]
contrib/android/res/values/strings.xml [new file with mode: 0644]
contrib/android/src/org/lisp/ecl/EmbeddedCommonLisp.java [new file with mode: 0644]
contrib/android/src/org/lisp/ecl/HelloEclActivity.java [new file with mode: 0644]

diff --git a/README.android b/README.android
new file mode 100644 (file)
index 0000000..83f2847
--- /dev/null
@@ -0,0 +1,12 @@
+To build:
+
+$ export ANDROID_NDK_ROOT=Path to NDK
+$ ./configure.android
+
+This will create a 32-bit version of ECL to cross-compile.
+Then it will compile an ARM 32-bit ECL into android/install/android.
+Please see the sample application in contrib/android.
+
+
+evrim ulu <evrimulu@gmail.com>
+March 2015
\ No newline at end of file
diff --git a/contrib/android/.classpath b/contrib/android/.classpath
new file mode 100644 (file)
index 0000000..7bc01d9
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="gen"/>
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+       <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+       <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+       <classpathentry kind="output" path="bin/classes"/>
+</classpath>
diff --git a/contrib/android/.project b/contrib/android/.project
new file mode 100644 (file)
index 0000000..508d720
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>HelloEclActivity</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/contrib/android/.settings/org.eclipse.jdt.core.prefs b/contrib/android/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..b080d2d
--- /dev/null
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/contrib/android/AndroidManifest.xml b/contrib/android/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..1a92913
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.lisp.ecl"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <uses-sdk android:minSdkVersion="19" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <application android:label="@string/app_name"
+                 android:debuggable="true">
+        <activity android:name="HelloEclActivity"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest> 
diff --git a/contrib/android/README b/contrib/android/README
new file mode 100644 (file)
index 0000000..6b17ee9
--- /dev/null
@@ -0,0 +1,14 @@
+This project is a base project for ECL Android.
+It is created by Sylvain Ageneau <ageneau@gmail.com>.
+Original location of this project is: 
+http://github.com/ageneau/ecl-android
+
+Instructions:
+$ android update project -t android-19 -p .
+$ ndk-build
+$ ant debug install
+
+Please direct further questions to ecl-lists@sf.net.
+
+evrim ulu <evrimulu@gmail.com>
+March 2015.
\ No newline at end of file
diff --git a/contrib/android/ant.properties b/contrib/android/ant.properties
new file mode 100644 (file)
index 0000000..b0971e8
--- /dev/null
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/contrib/android/assets/lisp/help.doc b/contrib/android/assets/lisp/help.doc
new file mode 100644 (file)
index 0000000..63b77bd
Binary files /dev/null and b/contrib/android/assets/lisp/help.doc differ
diff --git a/contrib/android/assets/lisp/init.lisp b/contrib/android/assets/lisp/init.lisp
new file mode 100644 (file)
index 0000000..a96aaad
--- /dev/null
@@ -0,0 +1,57 @@
+(in-package :cl-user)
+(format t "ECL (Embeddable Common-Lisp) ~A (git:~D)~%"
+       (lisp-implementation-version)
+       (ext:lisp-implementation-vcs-id))
+
+(require :SOCKETS)
+(require :ASDF)
+(setq *default-directory*
+      *default-pathname-defaults*)
+(defvar *ecl-home* *default-directory*)
+(ext:setenv "HOME" (namestring *ecl-home*))
+(pushnew (namestring *default-pathname-defaults*)
+        asdf:*central-registry*)
+(asdf:oos 'asdf:load-op :swank)
+(swank-loader:init :load-contribs t
+                  :setup t
+                  :delete t
+                  :quiet nil)
+
+;; The following "patches" swank to work correctly on android/iOS
+(in-package :swank/backend)
+(defimplementation lisp-implementation-program ()
+  "Return the argv[0] of the running Lisp process, or NIL."
+  ;; (lisp-implementation-type)
+  nil)
+
+(in-package :swank)
+(defun repl-input-stream-read (connection stdin)
+  (loop
+   (let* ((socket (connection.socket-io connection))
+          (inputs (list socket #+nil stdin))
+          (ready (wait-for-input inputs)))
+     (describe (list 'hobaa connection stdin socket inputs ready))
+     (cond ((eq ready :interrupt)
+            (check-slime-interrupts))
+           ((member socket ready)
+            ;; A Slime request from Emacs is pending; make sure to
+            ;; redirect IO to the REPL buffer.
+            (with-simple-restart (process-input "Continue reading input.")
+              (let ((*sldb-quit-restart* (find-restart 'process-input)))
+                (with-io-redirection (connection)
+                  (handle-requests connection t)))))
+           ((member stdin ready)
+            ;; User typed something into the  *inferior-lisp* buffer,
+            ;; so do not redirect.
+            (return (read-non-blocking stdin)))
+           (t (assert (null ready)))))))
+
+(mp:process-run-function
+ "SLIME-listener"
+ (lambda ()
+   (swank:create-server :port 4005
+                       :dont-close t)))
+
+(cond ((probe-file #P"user.lisp")
+       (load "user")))
+
diff --git a/contrib/android/assets/lisp/slime b/contrib/android/assets/lisp/slime
new file mode 160000 (submodule)
index 0000000..462085f
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 462085f1b7370e67babe9e7d50b37e5043c83fe1
diff --git a/contrib/android/assets/lisp/user.lisp b/contrib/android/assets/lisp/user.lisp
new file mode 100644 (file)
index 0000000..c0e9f28
--- /dev/null
@@ -0,0 +1,51 @@
+(in-package :cl-user)
+(require 'bytecmp)
+(setq *default-directory*
+      *default-pathname-defaults*)
+
+(defun sysinfo (&optional (out *standard-output*))
+  "Print the current environment to a stream."
+  (declare (stream out))
+  (format out "~&~%~75~~%~75,,,'-:@<<{[ The current environment ]}>~>~%~
+Implementation:~20t~a~%~7tversion:~20t~a~%Machine:  type:~20t~a
+~7tversion:~20t~a~%~6tinstance:~20t~a~%Opeating System:~19t"
+          (lisp-implementation-type) (lisp-implementation-version)
+          (machine-type) (machine-version) (machine-instance))
+  #+darwin (princ " Darwin")
+  #+unix (princ " Unix")
+  (format out "~%Software: type:~20t~a~%~7tversion:~20t~a~%Site:~20t~a (~a)
+User home:~20t~a~%Current directory:~20t~a~%Default pathname:~20t~a~%"
+          (software-type) (software-version) (long-site-name)
+          (short-site-name) (user-homedir-pathname) *default-directory*
+          *default-pathname-defaults*)
+  (format out "Features: ~s.
+Modules:~s.~%
+Current package:~s~%"
+           *features* *modules* *package*)
+  (flet ((exdi (fl) (integer-length (nth-value 1 (decode-float fl)))))
+    (format out "Fixnum length:~25t~3d bits
+Short Floats:~25t~3d bits exponent, ~3d bits significand (mantissa)
+Single Floats:~25t~3d bits exponent, ~3d bits significand (mantissa)
+Double Floats:~25t~3d bits exponent, ~3d bits significand (mantissa)
+Long Floats:~25t~3d bits exponent, ~3d bits significand (mantissa)~%"
+            (integer-length most-positive-fixnum)
+            (exdi most-positive-short-float)
+            (float-digits most-positive-short-float)
+            (exdi most-positive-single-float)
+            (float-digits most-positive-single-float)
+            (exdi most-positive-double-float)
+            (float-digits most-positive-double-float)
+            (exdi most-positive-long-float)
+            (float-digits most-positive-long-float)))
+  (dolist (sy '(array-total-size-limit array-rank-limit array-dimension-limit
+                lambda-parameters-limit call-arguments-limit
+                multiple-values-limit char-code-limit))
+    (format out " ~a:~30t~15:d~%" sy (symbol-value sy)))
+  (format out "lambda-list-keywords:~s~%"
+          lambda-list-keywords)
+  (format out "Internal time unit:~25t~f sec~%*gensym-counter*:~25t~:d
+Current time:~25t" (/ internal-time-units-per-second) *gensym-counter*)
+  (format out "~a" (get-universal-time))
+  (format out "~%~75~~%") (room) (values))
+
+(sysinfo)
diff --git a/contrib/android/build.xml b/contrib/android/build.xml
new file mode 100644 (file)
index 0000000..3e5e065
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="HelloEcl" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
diff --git a/contrib/android/jni/Android.mk b/contrib/android/jni/Android.mk
new file mode 100644 (file)
index 0000000..1784f06
--- /dev/null
@@ -0,0 +1,39 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# 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.
+#
+BASE_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+ifeq ($(TARGET_ARCH),x86)
+PLATFORM := androidx86
+else
+PLATFORM := android
+endif
+
+ECL_HOME := ../../android/install/$(PLATFORM)
+ECL_VER := $(shell basename $(ECL_HOME)/lib/ecl-* |cut -d "-" -f2)
+
+LOCAL_MODULE   := ecl_android
+LOCAL_PATH     := $(BASE_PATH)
+LOCAL_SRC_FILES := org_lisp_ecl_EmbeddedCommonLisp.c ecl_boot.c
+LOCAL_CFLAGS   += -I$(ECL_HOME)/include
+LOCAL_CFLAGS   += -g -Wall -DANDROID
+LOCAL_LDLIBS   := -L$(ECL_HOME)/lib 
+LOCAL_LDLIBS   += -L$(ECL_HOME)/lib/ecl-$(ECL_VER)
+LOCAL_LDLIBS   += -lecl -lasdf -leclgmp -lsockets -llog
+LOCAL_LDLIBS   += -lsb-bsd-sockets -lserve-event -lecl-help 
+LOCAL_LDLIBS   += -lecl-cdb -leclgc -leclatomic
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/contrib/android/jni/ecl_boot.c b/contrib/android/jni/ecl_boot.c
new file mode 100644 (file)
index 0000000..f6fcce7
--- /dev/null
@@ -0,0 +1,88 @@
+#include <stdlib.h>
+#include <ecl/ecl.h>
+#if ANDROID
+#include <android/log.h>
+#endif
+
+#if ANDROID
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
+#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
+#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))
+#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "native-activity", __VA_ARGS__))
+#else
+#define LOGI(...)
+#define LOGW(...)
+#define LOGE(...)
+#endif
+
+#include "ecl_boot.h"
+
+#ifdef __cplusplus
+#define ECL_CPP_TAG "C"
+#else
+#define ECL_CPP_TAG
+#endif
+
+extern ECL_CPP_TAG void main_lib_ASDF();
+extern ECL_CPP_TAG void main_lib_SOCKETS();
+extern ECL_CPP_TAG void main_lib_SB_BSD_SOCKETS();
+extern ECL_CPP_TAG void main_lib_SERVE_EVENT();
+extern ECL_CPP_TAG void main_lib_ECL_CDB();
+extern ECL_CPP_TAG void main_lib_ECL_HELP();
+
+
+extern void loadLispFromAssets(char* fn);
+
+
+int ecl_boot(const char *root_dir)
+{
+  char *ecl = "ecl";
+  char tmp[2048];
+
+  sprintf(tmp, "%s/", root_dir);
+  setenv("ECLDIR", tmp, 1);
+
+  // ecl_set_option(ECL_OPT_TRAP_SIGFPE, 0);
+  // ecl_set_option(ECL_OPT_TRAP_SIGSEGV, 0);
+  // ecl_set_option(ECL_OPT_TRAP_SIGINT, 0);
+  // ecl_set_option(ECL_OPT_TRAP_SIGILL, 0);
+  // ecl_set_option(ECL_OPT_TRAP_SIGBUS, 0);
+  // ecl_set_option(ECL_OPT_TRAP_INTERRUPT_SIGNAL, 0);
+  // ecl_set_option(ECL_OPT_SIGNAL_HANDLING_THREAD, 0);
+  // ecl_set_option(ECL_OPT_INCREMENTAL_GC, 0);
+
+  cl_boot(1, &ecl);
+
+  main_lib_ECL_HELP();
+  main_lib_ASDF();
+  main_lib_SOCKETS();
+
+  si_safe_eval(3, c_string_to_object("(format t \"ECL_BOOT, features = ~A ~%\" *features*)"), Cnil, OBJNULL);
+  si_safe_eval(3, c_string_to_object("(format t \"(truename SYS:): ~A)\" (truename \"SYS:\"))"), Cnil, OBJNULL);
+
+  LOGI("ALL LOADED\n");
+
+  ecl_toplevel(root_dir);
+
+  return 0;
+}
+
+void ecl_toplevel(const char *home)
+{
+  char tmp[2048];
+
+  LOGI("START TOP LEVEL\n");
+
+  CL_CATCH_ALL_BEGIN(ecl_process_env()) 
+  {
+         sprintf(tmp, "(setq *default-pathname-defaults* #p\"%s/\")", home);
+         si_safe_eval(3, c_string_to_object(tmp), Cnil, OBJNULL);
+
+         si_select_package(ecl_make_simple_base_string("CL-USER", 7));
+         
+         si_safe_eval(3, c_string_to_object("(load \"init\")"), Cnil, OBJNULL);
+
+  } CL_CATCH_ALL_END;
+
+  LOGI("EXIT TOP LEVEL\n");
+}
diff --git a/contrib/android/jni/ecl_boot.h b/contrib/android/jni/ecl_boot.h
new file mode 100644 (file)
index 0000000..4528407
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ECL_BOOT_H_
+#define _ECL_BOOT_H_
+
+int ecl_boot(const char *root_dir);
+void ecl_toplevel(const char *home);
+void eclshell_show(char *message);
+
+#endif
\ No newline at end of file
diff --git a/contrib/android/jni/org_lisp_ecl_EmbeddedCommonLisp.c b/contrib/android/jni/org_lisp_ecl_EmbeddedCommonLisp.c
new file mode 100644 (file)
index 0000000..2e6f85c
--- /dev/null
@@ -0,0 +1,134 @@
+#include <assert.h>
+
+#if ANDROID
+#include <android/log.h>
+#endif
+
+#include <string.h>
+#include <jni.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <ecl/ecl.h>
+#include "ecl_boot.h"
+
+#if ANDROID
+#define ECL_TAG "ecl-native"
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, ECL_TAG, __VA_ARGS__))
+#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, ECL_TAG, __VA_ARGS__))
+#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, ECL_TAG, __VA_ARGS__))
+#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ECL_TAG, __VA_ARGS__))
+#else
+#define LOGI(...)
+#define LOGW(...)
+#define LOGE(...)
+#endif
+
+#define jni_ecl_read_from_string(x) si_string_to_object(1, x)
+
+/*
+ * Class:     org_lisp_ecl_EmbeddedCommonLisp
+ * Method:    start
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_org_lisp_ecl_EmbeddedCommonLisp_start(JNIEnv *env, jobject this, 
+                                          jstring path) {
+
+  const char *lisp_dir = (*env)->GetStringUTFChars(env, path, NULL);  
+  LOGI("ECL starting: *default-pathname-defaults* to: %s\n", lisp_dir);
+  ecl_boot(lisp_dir);
+  LOGI("ECL started.");        
+};
+
+/* This was fun to make UTF8 work across Java-C-Lisp boundaries.
+   -evrim, 2014. */
+cl_object java_string_to_ecl_string(JNIEnv *env, jstring str) {
+  const jchar *txt = (*env)->GetStringChars(env, str, NULL);
+  jsize len = (*env)->GetStringLength(env, str);
+  cl_object ecl_txt = ecl_alloc_simple_extended_string(len);
+  cl_index i;
+
+  for (i=0;i<len;i++) {
+    ecl_txt->string.self[i] = txt[i];
+  };
+  
+  (*env)->ReleaseStringChars(env, str, txt);
+
+  return ecl_txt;
+}
+
+
+jstring ecl_object_to_java_string(JNIEnv *env, cl_object o) {
+  jstring ret;
+  if (ECL_EXTENDED_STRING_P(o)) {
+    LOGI("ecl->java extended string of fillp: %d, dim: %d",
+        o->string.fillp,
+        o->string.dim);
+    
+    jsize len = o->string.fillp;
+    jchar *arr = malloc(sizeof(jchar)*(len+1));
+    cl_index i;
+    for (i=0; i<len; i++) {
+      arr[i] = o->string.self[i];
+    }
+    arr[len] = 0;
+    ret = (*env)->NewString(env, arr, len);
+    free(arr);
+  } else if (ECL_STRINGP(o)) {
+    LOGI("ecl->java base string of len %d: %s",
+        o->base_string.dim,
+        o->base_string.self);
+
+    ret = (*env)->NewStringUTF(env, 
+                              (const char*)o->base_string.self);
+  } else {
+    LOGI("ecl->java not a string, coercing");
+    return ecl_object_to_java_string(env, cl_princ_to_string(o));
+  }
+
+  return ret;
+}
+
+/*
+ * Class:     org_lisp_ecl_EmbeddedCommonLisp
+ * Method:    exec
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_org_lisp_ecl_EmbeddedCommonLisp_exec(JNIEnv *env, jobject this, jstring str) {
+  jstring ret;
+  cl_object txt = java_string_to_ecl_string(env, str);
+  cl_object result = si_safe_eval(3, jni_ecl_read_from_string(txt), Cnil, OBJNULL);
+  
+  if (result) {
+    ret = ecl_object_to_java_string(env, result);
+  } else {
+    ret = (*env)->NewStringUTF(env, "ERROR in eval");
+  }
+  
+  return ret;
+};
+
+#undef jni_ecl_read_from_string
+
+/*
+ * Class:     org_lisp_ecl_EmbeddedCommonLisp
+ * Method:    exec_
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_org_lisp_ecl_EmbeddedCommonLisp_exec_(JNIEnv *env, jobject this, jstring str) {
+  jstring ret;
+  const char *cmd = (*env)->GetStringUTFChars(env, str, NULL);
+  cl_object result = si_safe_eval(3, c_string_to_object(cmd),
+                                 Cnil, OBJNULL);
+
+  if (result) {
+    cl_object out = si_coerce_to_base_string(cl_princ_to_string(result));
+    ret = (*env)->NewStringUTF(env, (const char*) out->base_string.self);
+  } else {
+    ret = (*env)->NewStringUTF(env, "ERROR in eval");
+  }
+  return ret;
+};
diff --git a/contrib/android/jni/org_lisp_ecl_EmbeddedCommonLisp.h b/contrib/android/jni/org_lisp_ecl_EmbeddedCommonLisp.h
new file mode 100644 (file)
index 0000000..9de49b3
--- /dev/null
@@ -0,0 +1,37 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_lisp_ecl_EmbeddedCommonLisp */
+
+#ifndef _Included_org_lisp_ecl_EmbeddedCommonLisp
+#define _Included_org_lisp_ecl_EmbeddedCommonLisp
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_lisp_ecl_EmbeddedCommonLisp
+ * Method:    start
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_lisp_ecl_EmbeddedCommonLisp_start
+(JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     org_lisp_ecl_EmbeddedCommonLisp
+ * Method:    exec
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_lisp_ecl_EmbeddedCommonLisp_exec
+(JNIEnv *, jobject, jstring);
+
+/* /\* */
+/*  * Class:     org_lisp_ecl_EmbeddedCommonLisp */
+/*  * Method:    botExec */
+/*  * Signature: (Ljava/lang/String;)Ljava/lang/String; */
+/*  *\/ */
+/* JNIEXPORT jstring JNICALL Java_org_lisp_ecl_EmbeddedCommonLisp_exec_ */
+/*   (JNIEnv *, jobject, jstring); */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/contrib/android/local.properties b/contrib/android/local.properties
new file mode 100644 (file)
index 0000000..16aace0
--- /dev/null
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/home/void/github/android-sdk
diff --git a/contrib/android/obj/local/armeabi/libhello-ecl.so b/contrib/android/obj/local/armeabi/libhello-ecl.so
new file mode 100755 (executable)
index 0000000..57409c0
Binary files /dev/null and b/contrib/android/obj/local/armeabi/libhello-ecl.so differ
diff --git a/contrib/android/proguard-project.txt b/contrib/android/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/contrib/android/project.properties b/contrib/android/project.properties
new file mode 100644 (file)
index 0000000..4ab1256
--- /dev/null
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-19
diff --git a/contrib/android/res/layout/main.xml b/contrib/android/res/layout/main.xml
new file mode 100644 (file)
index 0000000..a065c83
--- /dev/null
@@ -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"
+    >
+<TextView  
+    android:layout_width="fill_parent" 
+    android:layout_height="wrap_content" 
+    android:text="Hello World, HelloEclActivity"
+    />
+</LinearLayout>
+
diff --git a/contrib/android/res/layout/menu.xml b/contrib/android/res/layout/menu.xml
new file mode 100644 (file)
index 0000000..65b3bd6
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Single menu item
+         Set id, icon and Title for each menu item
+    -->
+    <item android:id="@+id/menu_uncompress"
+          android:title="Uncompress assets" /> 
+</menu>
diff --git a/contrib/android/res/values/strings.xml b/contrib/android/res/values/strings.xml
new file mode 100644 (file)
index 0000000..f846038
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">HelloEclActivity</string>
+</resources>
diff --git a/contrib/android/src/org/lisp/ecl/EmbeddedCommonLisp.java b/contrib/android/src/org/lisp/ecl/EmbeddedCommonLisp.java
new file mode 100644 (file)
index 0000000..b9b1ce3
--- /dev/null
@@ -0,0 +1,19 @@
+package org.lisp.ecl;
+
+import android.util.Log;
+
+public class EmbeddedCommonLisp {
+    private static String TAG = "EmbeddedCommonLisp";
+       
+    public void start() {
+       start(System.getenv("user.dir"));
+    }
+    public native void start(String path);
+    public native String exec(String string);
+    // public native String botExec(String string);
+
+    static {
+       System.loadLibrary("ecl_android");
+       Log.w(TAG,"Done loading library");
+    }
+}
diff --git a/contrib/android/src/org/lisp/ecl/HelloEclActivity.java b/contrib/android/src/org/lisp/ecl/HelloEclActivity.java
new file mode 100644 (file)
index 0000000..efd7454
--- /dev/null
@@ -0,0 +1,154 @@
+package org.lisp.ecl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.AssetManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+
+public class HelloEclActivity extends Activity
+{
+    private static String TAG = "HelloEcl";
+    private static String RESOURCES_DIR = "lisp";
+    private static String APP_RESOURCES_DIR = "resources";
+    private EmbeddedCommonLisp ecl = new EmbeddedCommonLisp();
+    
+    private static boolean DEBUG = false;
+
+       static AssetManager assetManager;
+       static File uncompressedFilesDir;
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        assetManager = getAssets();
+
+        SharedPreferences settings = getPreferences(MODE_PRIVATE);
+        boolean assetsUncompressed = settings.getBoolean("assetsUncompressed", false);
+        uncompressedFilesDir = getDir(APP_RESOURCES_DIR,MODE_PRIVATE);
+
+        if(!assetsUncompressed)
+        {
+               uncompressDir(RESOURCES_DIR,uncompressedFilesDir);
+               SharedPreferences.Editor editor = settings.edit();
+               editor.putBoolean("assetsUncompressed", true);
+               editor.commit();
+        }
+
+        Log.w(TAG,"ECL starting.");
+       
+
+        ecl.start(getResourcesPath());
+        Log.w(TAG,"ECL Started");
+
+        setContentView(R.layout.main);
+
+               String result = ecl.exec("(format nil \"Hello from lisp\")");
+               System.out.println("Result: " + result);
+               
+               Context context = getApplicationContext();
+               int duration = Toast.LENGTH_LONG;
+               
+               Toast toast = Toast.makeText(context, result, duration);
+               toast.show();
+    }
+
+    public void uncompressDir(String in, File out)
+    {
+        try
+               {
+            String[] files = assetManager.list(in);
+            Log.w(TAG,"Uncompressing: " + files.length + " files");
+            for(int i=0; i<files.length; i++)
+            {
+                Log.w(TAG,"Uncompressing: " + files[i]);
+                File fileIn = new File(in,files[i]);
+                File fileOut = new File(out,files[i]);
+
+                try
+                {
+                    uncompressFile(fileIn,fileOut);
+                }
+                catch(FileNotFoundException e)
+                {
+                    // fileIn is a directory, uncompress the subdir
+                    if(!fileOut.isDirectory())
+                    {
+                        Log.w(TAG,"Creating dir: " + fileOut.getAbsolutePath());
+                        fileOut.mkdir();
+                    }
+                    uncompressDir(fileIn.getPath(), fileOut);    
+                }
+            }
+               }
+               catch(IOException e)
+               {
+                       e.printStackTrace();
+               }
+    }
+
+       // Initiating Menu XML file (menu.xml)
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+        MenuInflater menuInflater = getMenuInflater();
+        menuInflater.inflate(R.layout.menu, menu);
+        return true;
+    }
+
+       /**
+     * Event Handling for Individual menu item selected
+     * Identify single menu item by it's id
+     * */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item)
+    {
+        switch (item.getItemId())
+        {
+        case R.id.menu_uncompress:
+               uncompressDir(RESOURCES_DIR,uncompressedFilesDir);
+               return true;
+        default:
+               return super.onOptionsItemSelected(item);
+        }
+    }
+
+       public static String getResourcesPath()
+       {
+               return uncompressedFilesDir.getAbsolutePath();
+       }
+
+       public static void uncompressFile(File fileIn,File fileOut)
+        throws IOException
+    {
+        InputStream in = assetManager.open(fileIn.getPath(),
+                                           android.content.res.AssetManager.ACCESS_RANDOM);
+               OutputStream out = new FileOutputStream(fileOut);
+
+               byte[] buf = new byte[1024];
+               int len;
+               while ((len = in.read(buf)) > 0)
+               {
+                       out.write(buf, 0, len);
+               }
+
+               in.close();
+               out.close();
+               Log.i(TAG,"File copied.");
+    }    
+}