mobile: add sample android application (HelloECL)
Developed by Sylvain Agenau, added to the repository by Evrim Ulu with a few minor fixes by Daniel Kochmański.
This commit is contained in:
parent
d7776157d6
commit
641a12b4e1
21 changed files with 753 additions and 0 deletions
12
README.android
Normal file
12
README.android
Normal file
|
|
@ -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
|
||||
9
examples/android/.classpath
Normal file
9
examples/android/.classpath
Normal file
|
|
@ -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>
|
||||
33
examples/android/.project
Normal file
33
examples/android/.project
Normal file
|
|
@ -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>
|
||||
4
examples/android/.settings/org.eclipse.jdt.core.prefs
Normal file
4
examples/android/.settings/org.eclipse.jdt.core.prefs
Normal file
|
|
@ -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
|
||||
18
examples/android/AndroidManifest.xml
Normal file
18
examples/android/AndroidManifest.xml
Normal file
|
|
@ -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>
|
||||
14
examples/android/README
Normal file
14
examples/android/README
Normal file
|
|
@ -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-devel@common-lisp.net
|
||||
|
||||
evrim ulu <evrimulu@gmail.com>
|
||||
March 2015.
|
||||
17
examples/android/ant.properties
Normal file
17
examples/android/ant.properties
Normal file
|
|
@ -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.
|
||||
|
||||
57
examples/android/assets/lisp/init.lisp
Normal file
57
examples/android/assets/lisp/init.lisp
Normal file
|
|
@ -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")))
|
||||
|
||||
51
examples/android/assets/lisp/user.lisp
Normal file
51
examples/android/assets/lisp/user.lisp
Normal file
|
|
@ -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)
|
||||
39
examples/android/jni/Android.mk
Normal file
39
examples/android/jni/Android.mk
Normal file
|
|
@ -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)
|
||||
88
examples/android/jni/ecl_boot.c
Normal file
88
examples/android/jni/ecl_boot.c
Normal file
|
|
@ -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");
|
||||
}
|
||||
8
examples/android/jni/ecl_boot.h
Normal file
8
examples/android/jni/ecl_boot.h
Normal file
|
|
@ -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
|
||||
134
examples/android/jni/org_lisp_ecl_EmbeddedCommonLisp.c
Normal file
134
examples/android/jni/org_lisp_ecl_EmbeddedCommonLisp.c
Normal file
|
|
@ -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;
|
||||
};
|
||||
37
examples/android/jni/org_lisp_ecl_EmbeddedCommonLisp.h
Normal file
37
examples/android/jni/org_lisp_ecl_EmbeddedCommonLisp.h
Normal file
|
|
@ -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
|
||||
20
examples/android/proguard-project.txt
Normal file
20
examples/android/proguard-project.txt
Normal file
|
|
@ -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 *;
|
||||
#}
|
||||
14
examples/android/project.properties
Normal file
14
examples/android/project.properties
Normal file
|
|
@ -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
|
||||
13
examples/android/res/layout/main.xml
Normal file
13
examples/android/res/layout/main.xml
Normal 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"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, HelloEclActivity"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
8
examples/android/res/layout/menu.xml
Normal file
8
examples/android/res/layout/menu.xml
Normal file
|
|
@ -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>
|
||||
4
examples/android/res/values/strings.xml
Normal file
4
examples/android/res/values/strings.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">HelloEclActivity</string>
|
||||
</resources>
|
||||
19
examples/android/src/org/lisp/ecl/EmbeddedCommonLisp.java
Normal file
19
examples/android/src/org/lisp/ecl/EmbeddedCommonLisp.java
Normal file
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
154
examples/android/src/org/lisp/ecl/HelloEclActivity.java
Normal file
154
examples/android/src/org/lisp/ecl/HelloEclActivity.java
Normal file
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue