ruboto 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +19 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +21 -0
- data/README.md +293 -0
- data/Rakefile +114 -0
- data/assets/Rakefile +386 -0
- data/assets/res/drawable-hdpi/icon.png +0 -0
- data/assets/res/drawable-ldpi/icon.png +0 -0
- data/assets/res/drawable-mdpi/icon.png +0 -0
- data/assets/res/layout/get_ruboto_core.xml +25 -0
- data/assets/samples/sample_activity.rb +21 -0
- data/assets/samples/sample_activity_test.rb +21 -0
- data/assets/samples/sample_broadcast_receiver.rb +6 -0
- data/assets/samples/sample_broadcast_receiver_test.rb +1 -0
- data/assets/samples/sample_service.rb +14 -0
- data/assets/samples/sample_service_test.rb +1 -0
- data/assets/src/InheritingActivity.java +195 -0
- data/assets/src/InheritingBroadcastReceiver.java +27 -0
- data/assets/src/InheritingClass.java +19 -0
- data/assets/src/InheritingService.java +9 -0
- data/assets/src/RubotoActivity.java +111 -0
- data/assets/src/RubotoBroadcastReceiver.java +51 -0
- data/assets/src/RubotoService.java +61 -0
- data/assets/src/org/ruboto/RubotoDialog.java +11 -0
- data/assets/src/org/ruboto/Script.java +545 -0
- data/assets/src/org/ruboto/test/ActivityTest.java +63 -0
- data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +124 -0
- data/assets/src/ruboto.rb +621 -0
- data/assets/test/assets/scripts/test_helper.rb +13 -0
- data/bin/ruboto +5 -0
- data/lib/java_class_gen/InheritingClass.java.erb +10 -0
- data/lib/java_class_gen/android_api.xml +1 -0
- data/lib/ruboto.rb +16 -0
- data/lib/ruboto/api.rb +21 -0
- data/lib/ruboto/commands/base.rb +392 -0
- data/lib/ruboto/core_ext/array.rb +6 -0
- data/lib/ruboto/core_ext/object.rb +10 -0
- data/lib/ruboto/util/asset_copier.rb +27 -0
- data/lib/ruboto/util/build.rb +201 -0
- data/lib/ruboto/util/code_formatting.rb +22 -0
- data/lib/ruboto/util/log_action.rb +20 -0
- data/lib/ruboto/util/main_fix.rb +13 -0
- data/lib/ruboto/util/objectspace.rb +8 -0
- data/lib/ruboto/util/scan_in_api.rb +40 -0
- data/lib/ruboto/util/update.rb +420 -0
- data/lib/ruboto/util/verify.rb +87 -0
- data/lib/ruboto/util/xml_element.rb +200 -0
- data/lib/ruboto/version.rb +3 -0
- data/test/activity/image_button_activity.rb +21 -0
- data/test/activity/image_button_activity_test.rb +21 -0
- data/test/activity/image_button_and_button_activity.rb +24 -0
- data/test/activity/image_button_and_button_activity_test.rb +27 -0
- data/test/activity/option_menu_activity.rb +21 -0
- data/test/activity/option_menu_activity_test.rb +20 -0
- data/test/activity/stack_activity.rb +21 -0
- data/test/activity/stack_activity_test.rb +23 -0
- data/test/app_test_methods.rb +41 -0
- data/test/minimal_app_test.rb +23 -0
- data/test/rake_test.rb +40 -0
- data/test/ruboto_gen_test.rb +32 -0
- data/test/ruboto_gen_with_psych_test.rb +16 -0
- data/test/ruboto_update_test.rb +5 -0
- data/test/ruboto_update_with_psych_test.rb +18 -0
- data/test/service_test.rb +49 -0
- data/test/test_helper.rb +177 -0
- data/test/update_test_methods.rb +33 -0
- metadata +157 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
package THE_PACKAGE;
|
2
|
+
|
3
|
+
import org.ruboto.Script;
|
4
|
+
import java.io.IOException;
|
5
|
+
import android.app.ProgressDialog;
|
6
|
+
|
7
|
+
public abstract class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
|
8
|
+
private String scriptName;
|
9
|
+
private String remoteVariable = "";
|
10
|
+
public Object[] args;
|
11
|
+
|
12
|
+
THE_CONSTANTS
|
13
|
+
|
14
|
+
private Object[] callbackProcs = new Object[CONSTANTS_COUNT];
|
15
|
+
|
16
|
+
public void setCallbackProc(int id, Object obj) {
|
17
|
+
callbackProcs[id] = obj;
|
18
|
+
}
|
19
|
+
|
20
|
+
public THE_RUBOTO_CLASS setRemoteVariable(String var) {
|
21
|
+
remoteVariable = ((var == null) ? "" : (var + "."));
|
22
|
+
return this;
|
23
|
+
}
|
24
|
+
|
25
|
+
public void setScriptName(String name){
|
26
|
+
scriptName = name;
|
27
|
+
}
|
28
|
+
|
29
|
+
/****************************************************************************************
|
30
|
+
*
|
31
|
+
* Activity Lifecycle: onCreate
|
32
|
+
*/
|
33
|
+
|
34
|
+
@Override
|
35
|
+
public void onCreate() {
|
36
|
+
args = new Object[0];
|
37
|
+
|
38
|
+
super.onCreate();
|
39
|
+
|
40
|
+
if (Script.setUpJRuby(this)) {
|
41
|
+
Script.defineGlobalVariable("$service", this);
|
42
|
+
try {
|
43
|
+
new Script(scriptName).execute();
|
44
|
+
} catch(IOException e) {
|
45
|
+
e.printStackTrace();
|
46
|
+
}
|
47
|
+
} else {
|
48
|
+
// FIXME(uwe): What to do if the Ruboto Core plarform cannot be found?
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
/****************************************************************************************
|
53
|
+
*
|
54
|
+
* Generated Methods
|
55
|
+
*/
|
56
|
+
|
57
|
+
THE_METHODS
|
58
|
+
|
59
|
+
}
|
60
|
+
|
61
|
+
|
@@ -0,0 +1,545 @@
|
|
1
|
+
package org.ruboto;
|
2
|
+
|
3
|
+
import android.content.Context;
|
4
|
+
import android.content.Intent;
|
5
|
+
import android.content.pm.ApplicationInfo;
|
6
|
+
import android.content.pm.PackageInfo;
|
7
|
+
import android.content.pm.PackageManager;
|
8
|
+
import android.content.pm.PackageManager.NameNotFoundException;
|
9
|
+
import android.content.res.AssetManager;
|
10
|
+
import android.net.Uri;
|
11
|
+
import android.os.Environment;
|
12
|
+
import android.util.Log;
|
13
|
+
|
14
|
+
import java.io.BufferedOutputStream;
|
15
|
+
import java.io.BufferedReader;
|
16
|
+
import java.io.File;
|
17
|
+
import java.io.FileOutputStream;
|
18
|
+
import java.io.FileReader;
|
19
|
+
import java.io.FilenameFilter;
|
20
|
+
import java.io.IOException;
|
21
|
+
import java.io.InputStream;
|
22
|
+
import java.io.OutputStream;
|
23
|
+
import java.io.PrintStream;
|
24
|
+
import java.lang.reflect.InvocationTargetException;
|
25
|
+
import java.lang.reflect.Method;
|
26
|
+
import java.util.List;
|
27
|
+
|
28
|
+
import dalvik.system.PathClassLoader;
|
29
|
+
|
30
|
+
public class Script {
|
31
|
+
private static String scriptsDir = "scripts";
|
32
|
+
private static File scriptsDirFile = null;
|
33
|
+
|
34
|
+
private String name = null;
|
35
|
+
private static Object ruby;
|
36
|
+
private static boolean initialized = false;
|
37
|
+
|
38
|
+
private static String localContextScope = "SINGLETON";
|
39
|
+
private static String localVariableBehavior = "TRANSIENT";
|
40
|
+
|
41
|
+
public static final String TAG = "RUBOTO"; // for logging
|
42
|
+
private static String JRUBY_VERSION;
|
43
|
+
|
44
|
+
/*************************************************************************************************
|
45
|
+
*
|
46
|
+
* Static Methods: ScriptingContainer config
|
47
|
+
*/
|
48
|
+
|
49
|
+
public static void setLocalContextScope(String val) {
|
50
|
+
localContextScope = val;
|
51
|
+
}
|
52
|
+
|
53
|
+
public static void setLocalVariableBehavior(String val) {
|
54
|
+
localVariableBehavior = val;
|
55
|
+
}
|
56
|
+
|
57
|
+
/*************************************************************************************************
|
58
|
+
*
|
59
|
+
* Static Methods: JRuby Execution
|
60
|
+
*/
|
61
|
+
|
62
|
+
public static final FilenameFilter RUBY_FILES = new FilenameFilter() {
|
63
|
+
public boolean accept(File dir, String fname) {
|
64
|
+
return fname.endsWith(".rb");
|
65
|
+
}
|
66
|
+
};
|
67
|
+
|
68
|
+
public static synchronized boolean isInitialized() {
|
69
|
+
return initialized;
|
70
|
+
}
|
71
|
+
|
72
|
+
public static synchronized boolean setUpJRuby(Context appContext) {
|
73
|
+
return setUpJRuby(appContext, System.out);
|
74
|
+
}
|
75
|
+
|
76
|
+
public static synchronized boolean setUpJRuby(Context appContext, PrintStream out) {
|
77
|
+
if (!initialized) {
|
78
|
+
Log.d(TAG, "Setting up JRuby runtime");
|
79
|
+
System.setProperty("jruby.bytecode.version", "1.5");
|
80
|
+
System.setProperty("jruby.interfaces.useProxy", "true");
|
81
|
+
System.setProperty("jruby.management.enabled", "false");
|
82
|
+
System.setProperty("jruby.objectspace.enabled", "false");
|
83
|
+
System.setProperty("jruby.thread.pooling", "true");
|
84
|
+
System.setProperty("jruby.native.enabled", "false");
|
85
|
+
|
86
|
+
// Uncomment these to debug Ruby source loading
|
87
|
+
// System.setProperty("jruby.debug.loadService", "true");
|
88
|
+
// System.setProperty("jruby.debug.loadService.timing", "true");
|
89
|
+
|
90
|
+
|
91
|
+
ClassLoader classLoader;
|
92
|
+
Class<?> scriptingContainerClass;
|
93
|
+
String apkName = null;
|
94
|
+
|
95
|
+
try {
|
96
|
+
scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer");
|
97
|
+
System.out.println("Found JRuby in this APK");
|
98
|
+
classLoader = Script.class.getClassLoader();
|
99
|
+
try {
|
100
|
+
apkName = appContext.getPackageManager().getApplicationInfo(appContext.getPackageName(), 0).sourceDir;
|
101
|
+
} catch (NameNotFoundException e) {}
|
102
|
+
} catch (ClassNotFoundException e1) {
|
103
|
+
String packageName = "org.ruboto.core";
|
104
|
+
try {
|
105
|
+
apkName = appContext.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;
|
106
|
+
} catch (PackageManager.NameNotFoundException e) {
|
107
|
+
System.out.println("JRuby not found");
|
108
|
+
return false;
|
109
|
+
}
|
110
|
+
|
111
|
+
System.out.println("Found JRuby in platform APK");
|
112
|
+
if (true) {
|
113
|
+
classLoader = new PathClassLoader(apkName, Script.class.getClassLoader());
|
114
|
+
} else {
|
115
|
+
// Alternative way to get the class loader. The other way is rumoured to have memory leaks.
|
116
|
+
try {
|
117
|
+
Context platformAppContext = appContext.createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE + Context.CONTEXT_IGNORE_SECURITY);
|
118
|
+
classLoader = platformAppContext.getClassLoader();
|
119
|
+
} catch (PackageManager.NameNotFoundException e) {
|
120
|
+
System.out.println("Could not create package context even if application info could be found. Should never happen.");
|
121
|
+
return false;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
try {
|
126
|
+
scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, classLoader);
|
127
|
+
} catch (ClassNotFoundException e) {
|
128
|
+
// FIXME(uwe): ScriptingContainer not found in the platform APK...
|
129
|
+
e.printStackTrace();
|
130
|
+
return false;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
try {
|
135
|
+
try {
|
136
|
+
JRUBY_VERSION = (String) Class.forName("org.jruby.runtime.Constants", true, classLoader).getDeclaredField("VERSION").get(String.class);
|
137
|
+
} catch (java.lang.NoSuchFieldException nsfex) {
|
138
|
+
nsfex.printStackTrace();
|
139
|
+
JRUBY_VERSION = "ERROR";
|
140
|
+
}
|
141
|
+
|
142
|
+
Class scopeClass = Class.forName("org.jruby.embed.LocalContextScope", true, scriptingContainerClass.getClassLoader());
|
143
|
+
Class behaviorClass = Class.forName("org.jruby.embed.LocalVariableBehavior", true, scriptingContainerClass.getClassLoader());
|
144
|
+
|
145
|
+
ruby = scriptingContainerClass
|
146
|
+
.getConstructor(scopeClass, behaviorClass)
|
147
|
+
.newInstance(Enum.valueOf(scopeClass, localContextScope),
|
148
|
+
Enum.valueOf(behaviorClass, localVariableBehavior));
|
149
|
+
|
150
|
+
Class compileModeClass = Class.forName("org.jruby.RubyInstanceConfig$CompileMode", true, classLoader);
|
151
|
+
callScriptingContainerMethod(Void.class, "setCompileMode", Enum.valueOf(compileModeClass, "OFF"));
|
152
|
+
|
153
|
+
// Class traceTypeClass = Class.forName("org.jruby.runtime.backtrace.TraceType", true, classLoader);
|
154
|
+
// Method traceTypeForMethod = traceTypeClass.getMethod("traceTypeFor", String.class);
|
155
|
+
// Object traceTypeRaw = traceTypeForMethod.invoke(null, "raw");
|
156
|
+
// callScriptingContainerMethod(Void.class, "setTraceType", traceTypeRaw);
|
157
|
+
|
158
|
+
// FIXME(uwe): Write tutorial on profiling.
|
159
|
+
// container.getProvider().getRubyInstanceConfig().setProfilingMode(mode);
|
160
|
+
|
161
|
+
// callScriptingContainerMethod(Void.class, "setClassLoader", classLoader);
|
162
|
+
Method setClassLoaderMethod = ruby.getClass().getMethod("setClassLoader", ClassLoader.class);
|
163
|
+
setClassLoaderMethod.invoke(ruby, classLoader);
|
164
|
+
|
165
|
+
Thread.currentThread().setContextClassLoader(classLoader);
|
166
|
+
|
167
|
+
String defaultCurrentDir = appContext.getFilesDir().getPath();
|
168
|
+
Log.d(TAG, "Setting JRuby current directory to " + defaultCurrentDir);
|
169
|
+
callScriptingContainerMethod(Void.class, "setCurrentDirectory", defaultCurrentDir);
|
170
|
+
|
171
|
+
if (out != null) {
|
172
|
+
// callScriptingContainerMethod(Void.class, "setOutput", out);
|
173
|
+
Method setOutputMethod = ruby.getClass().getMethod("setOutput", PrintStream.class);
|
174
|
+
setOutputMethod.invoke(ruby, out);
|
175
|
+
|
176
|
+
// callScriptingContainerMethod(Void.class, "setError", out);
|
177
|
+
Method setErrorMethod = ruby.getClass().getMethod("setError", PrintStream.class);
|
178
|
+
setErrorMethod.invoke(ruby, out);
|
179
|
+
}
|
180
|
+
|
181
|
+
String jrubyHome = "file:" + apkName + "!";
|
182
|
+
Log.i(TAG, "Setting JRUBY_HOME: " + jrubyHome);
|
183
|
+
System.setProperty("jruby.home", jrubyHome);
|
184
|
+
|
185
|
+
String extraScriptsDir = scriptsDirName(appContext);
|
186
|
+
Log.i(TAG, "Checking scripts in " + extraScriptsDir);
|
187
|
+
if (configDir(extraScriptsDir)) {
|
188
|
+
Log.i(TAG, "Added extra scripts path: " + extraScriptsDir);
|
189
|
+
}
|
190
|
+
initialized = true;
|
191
|
+
} catch (ClassNotFoundException e) {
|
192
|
+
handleInitException(e);
|
193
|
+
} catch (IllegalArgumentException e) {
|
194
|
+
handleInitException(e);
|
195
|
+
} catch (SecurityException e) {
|
196
|
+
handleInitException(e);
|
197
|
+
} catch (InstantiationException e) {
|
198
|
+
handleInitException(e);
|
199
|
+
} catch (IllegalAccessException e) {
|
200
|
+
handleInitException(e);
|
201
|
+
} catch (InvocationTargetException e) {
|
202
|
+
handleInitException(e);
|
203
|
+
} catch (NoSuchMethodException e) {
|
204
|
+
handleInitException(e);
|
205
|
+
}
|
206
|
+
}
|
207
|
+
return initialized;
|
208
|
+
}
|
209
|
+
|
210
|
+
private static void handleInitException(Exception e) {
|
211
|
+
Log.e(TAG, "Exception starting JRuby");
|
212
|
+
Log.e(TAG, e.getMessage() != null ? e.getMessage() : e.getClass().getName());
|
213
|
+
e.printStackTrace();
|
214
|
+
ruby = null;
|
215
|
+
}
|
216
|
+
|
217
|
+
@SuppressWarnings("unchecked")
|
218
|
+
public static <T> T callScriptingContainerMethod(Class<T> returnType, String methodName, Object... args) {
|
219
|
+
Class<?>[] argClasses = new Class[args.length];
|
220
|
+
for (int i = 0; i < argClasses.length; i++) {
|
221
|
+
argClasses[i] = args[i].getClass();
|
222
|
+
}
|
223
|
+
try {
|
224
|
+
Method method = ruby.getClass().getMethod(methodName, argClasses);
|
225
|
+
System.out.println("callScriptingContainerMethod: method: " + method);
|
226
|
+
T result = (T) method.invoke(ruby, args);
|
227
|
+
System.out.println("callScriptingContainerMethod: result: " + result);
|
228
|
+
return result;
|
229
|
+
} catch (RuntimeException re) {
|
230
|
+
re.printStackTrace();
|
231
|
+
} catch (IllegalAccessException e) {
|
232
|
+
// TODO Auto-generated catch block
|
233
|
+
e.printStackTrace();
|
234
|
+
} catch (InvocationTargetException e) {
|
235
|
+
try {
|
236
|
+
e.printStackTrace();
|
237
|
+
} catch (NullPointerException npe) {
|
238
|
+
}
|
239
|
+
} catch (NoSuchMethodException e) {
|
240
|
+
// TODO Auto-generated catch block
|
241
|
+
e.printStackTrace();
|
242
|
+
}
|
243
|
+
return null;
|
244
|
+
}
|
245
|
+
|
246
|
+
public static String execute(String code) {
|
247
|
+
Object result = exec(code);
|
248
|
+
return result != null ? result.toString() : "nil";
|
249
|
+
// TODO: Why is callMethod returning "main"?
|
250
|
+
// return result != null ? callMethod(result, "inspect", String.class) : "null";
|
251
|
+
}
|
252
|
+
|
253
|
+
public static Object exec(String code) {
|
254
|
+
// return callScriptingContainerMethod(Object.class, "runScriptlet", code);
|
255
|
+
try {
|
256
|
+
Method runScriptletMethod = ruby.getClass().getMethod("runScriptlet", String.class);
|
257
|
+
return runScriptletMethod.invoke(ruby, code);
|
258
|
+
} catch (NoSuchMethodException nsme) {
|
259
|
+
throw new RuntimeException(nsme);
|
260
|
+
} catch (IllegalAccessException iae) {
|
261
|
+
throw new RuntimeException(iae);
|
262
|
+
} catch (java.lang.reflect.InvocationTargetException ite) {
|
263
|
+
throw ((RuntimeException) ite.getCause());
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
public static void defineGlobalConstant(String name, Object object) {
|
268
|
+
put(name, object);
|
269
|
+
}
|
270
|
+
|
271
|
+
public static void put(String name, Object object) {
|
272
|
+
// callScriptingContainerMethod(Void.class, "put", name, object);
|
273
|
+
try {
|
274
|
+
Method putMethod = ruby.getClass().getMethod("put", String.class, Object.class);
|
275
|
+
putMethod.invoke(ruby, name, object);
|
276
|
+
} catch (NoSuchMethodException nsme) {
|
277
|
+
throw new RuntimeException(nsme);
|
278
|
+
} catch (IllegalAccessException iae) {
|
279
|
+
throw new RuntimeException(iae);
|
280
|
+
} catch (java.lang.reflect.InvocationTargetException ite) {
|
281
|
+
throw new RuntimeException(ite);
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
public static void defineGlobalVariable(String name, Object object) {
|
286
|
+
defineGlobalConstant(name, object);
|
287
|
+
}
|
288
|
+
|
289
|
+
/*************************************************************************************************
|
290
|
+
*
|
291
|
+
* Static Methods: Scripts Directory
|
292
|
+
*/
|
293
|
+
|
294
|
+
public static void setDir(String dir) {
|
295
|
+
scriptsDir = dir;
|
296
|
+
scriptsDirFile = new File(dir);
|
297
|
+
if (ruby != null) {
|
298
|
+
Log.d(TAG, "Changing JRuby current directory to " + scriptsDir);
|
299
|
+
callScriptingContainerMethod(Void.class, "setCurrentDirectory", scriptsDir);
|
300
|
+
}
|
301
|
+
}
|
302
|
+
|
303
|
+
public static String getDir() {
|
304
|
+
return scriptsDir;
|
305
|
+
}
|
306
|
+
|
307
|
+
public static File getDirFile() {
|
308
|
+
return scriptsDirFile;
|
309
|
+
}
|
310
|
+
|
311
|
+
private static void setLoadPath(List<String> loadPath) {
|
312
|
+
// callScriptingContainerMethod(Void.class, "setLoadPaths", loadPath);
|
313
|
+
try {
|
314
|
+
Method setLoadPathsMethod = ruby.getClass().getMethod("setLoadPaths", List.class);
|
315
|
+
setLoadPathsMethod.invoke(ruby, loadPath);
|
316
|
+
} catch (NoSuchMethodException nsme) {
|
317
|
+
throw new RuntimeException(nsme);
|
318
|
+
} catch (IllegalAccessException iae) {
|
319
|
+
throw new RuntimeException(iae);
|
320
|
+
} catch (java.lang.reflect.InvocationTargetException ite) {
|
321
|
+
throw new RuntimeException(ite);
|
322
|
+
}
|
323
|
+
}
|
324
|
+
|
325
|
+
private static List<String> getLoadPath() {
|
326
|
+
return callScriptingContainerMethod(List.class, "getLoadPaths");
|
327
|
+
}
|
328
|
+
|
329
|
+
public static Boolean configDir(String scriptsDir) {
|
330
|
+
if (new File(scriptsDir).exists()) {
|
331
|
+
Log.i(TAG, "Found extra scripts dir: " + scriptsDir);
|
332
|
+
setDir(scriptsDir);
|
333
|
+
exec("$:.unshift '" + scriptsDir + "' ; $:.uniq! ; p $:");
|
334
|
+
return true;
|
335
|
+
} else {
|
336
|
+
Log.i(TAG, "Extra scripts dir not present: " + scriptsDir);
|
337
|
+
return false;
|
338
|
+
}
|
339
|
+
}
|
340
|
+
|
341
|
+
private static void copyScripts(String from, File to, AssetManager assets) {
|
342
|
+
try {
|
343
|
+
byte[] buffer = new byte[8192];
|
344
|
+
for (String f : assets.list(from)) {
|
345
|
+
File dest = new File(to, f);
|
346
|
+
|
347
|
+
if (dest.exists()) {
|
348
|
+
continue;
|
349
|
+
}
|
350
|
+
|
351
|
+
Log.d(TAG, "copying file from " + from + "/" + f + " to " + dest);
|
352
|
+
|
353
|
+
if (assets.list(from + "/" + f).length == 0) {
|
354
|
+
InputStream is = assets.open(from + "/" + f);
|
355
|
+
OutputStream fos = new BufferedOutputStream(new FileOutputStream(dest), 8192);
|
356
|
+
|
357
|
+
int n;
|
358
|
+
while ((n = is.read(buffer, 0, buffer.length)) != -1) {
|
359
|
+
fos.write(buffer, 0, n);
|
360
|
+
}
|
361
|
+
is.close();
|
362
|
+
fos.close();
|
363
|
+
} else {
|
364
|
+
dest.mkdir();
|
365
|
+
copyScripts(from + "/" + f, dest, assets);
|
366
|
+
}
|
367
|
+
}
|
368
|
+
} catch (IOException iox) {
|
369
|
+
Log.e(TAG, "error copying scripts", iox);
|
370
|
+
}
|
371
|
+
}
|
372
|
+
|
373
|
+
public static void copyAssets(Context context, String directory) {
|
374
|
+
File dest = new File(scriptsDirFile.getParentFile(), directory);
|
375
|
+
if (dest.exists() || dest.mkdir()) {
|
376
|
+
copyScripts(directory, dest, context.getAssets());
|
377
|
+
} else {
|
378
|
+
throw new RuntimeException("Unable to create scripts directory: " + dest);
|
379
|
+
}
|
380
|
+
}
|
381
|
+
|
382
|
+
private static boolean isDebugBuild(Context context) {
|
383
|
+
PackageManager pm = context.getPackageManager();
|
384
|
+
PackageInfo pi;
|
385
|
+
try {
|
386
|
+
pi = pm.getPackageInfo(context.getPackageName(), 0);
|
387
|
+
return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
|
388
|
+
} catch (NameNotFoundException e) {
|
389
|
+
return false;
|
390
|
+
}
|
391
|
+
|
392
|
+
}
|
393
|
+
|
394
|
+
private static String scriptsDirName(Context context) {
|
395
|
+
File storageDir = null;
|
396
|
+
if (isDebugBuild(context)) {
|
397
|
+
|
398
|
+
// FIXME(uwe): Simplify this as soon as we drop support for android-7 or JRuby 1.5.6 or JRuby 1.6.2
|
399
|
+
Log.i(TAG, "JRuby VERSION: " + JRUBY_VERSION);
|
400
|
+
if (!JRUBY_VERSION.equals("1.5.6") && !JRUBY_VERSION.equals("1.6.2") && android.os.Build.VERSION.SDK_INT >= 8) {
|
401
|
+
put("script_context", context);
|
402
|
+
storageDir = (File) exec("script_context.getExternalFilesDir(nil)");
|
403
|
+
} else {
|
404
|
+
storageDir = new File(Environment.getExternalStorageDirectory(), "Android/data/" + context.getPackageName() + "/files");
|
405
|
+
Log.e(TAG, "Calculated path to sdcard the old way: " + storageDir);
|
406
|
+
}
|
407
|
+
// FIXME end
|
408
|
+
|
409
|
+
if (storageDir == null || (!storageDir.exists() && !storageDir.mkdirs())) {
|
410
|
+
Log.e(TAG,
|
411
|
+
"Development mode active, but sdcard is not available. Make sure you have added\n<uses-permission android:name='android.permission.WRITE_EXTERNAL_STORAGE' />\nto your AndroidManifest.xml file.");
|
412
|
+
storageDir = context.getFilesDir();
|
413
|
+
}
|
414
|
+
} else {
|
415
|
+
storageDir = context.getFilesDir();
|
416
|
+
}
|
417
|
+
return storageDir.getAbsolutePath() + "/scripts";
|
418
|
+
}
|
419
|
+
|
420
|
+
private static void copyScriptsIfNeeded(Context context) {
|
421
|
+
String to = scriptsDirName(context);
|
422
|
+
Log.i(TAG, "Checking scripts in " + to);
|
423
|
+
|
424
|
+
/* the if makes sure we only do this the first time */
|
425
|
+
if (configDir(to)) {
|
426
|
+
Log.i(TAG, "Copying scripts to " + to);
|
427
|
+
copyAssets(context, "scripts");
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
|
432
|
+
/*************************************************************************************************
|
433
|
+
*
|
434
|
+
* Constructors
|
435
|
+
*/
|
436
|
+
|
437
|
+
public Script(String name) {
|
438
|
+
this.name = name;
|
439
|
+
}
|
440
|
+
|
441
|
+
/*************************************************************************************************
|
442
|
+
*
|
443
|
+
* Attribute Access
|
444
|
+
*/
|
445
|
+
|
446
|
+
public String getName() {
|
447
|
+
return name;
|
448
|
+
}
|
449
|
+
|
450
|
+
public File getFile() {
|
451
|
+
return new File(getDir(), name);
|
452
|
+
}
|
453
|
+
|
454
|
+
public Script setName(String name) {
|
455
|
+
this.name = name;
|
456
|
+
return this;
|
457
|
+
}
|
458
|
+
|
459
|
+
public String getContents() throws IOException {
|
460
|
+
InputStream is;
|
461
|
+
if (new File(scriptsDir + "/" + name).exists()) {
|
462
|
+
is = new java.io.FileInputStream(scriptsDir + "/" + name);
|
463
|
+
} else {
|
464
|
+
is = getClass().getClassLoader().getResourceAsStream(name);
|
465
|
+
}
|
466
|
+
BufferedReader buffer = new BufferedReader(new java.io.InputStreamReader(is), 8192);
|
467
|
+
StringBuilder source = new StringBuilder();
|
468
|
+
while (true) {
|
469
|
+
String line = buffer.readLine();
|
470
|
+
if (line == null) {
|
471
|
+
break;
|
472
|
+
}
|
473
|
+
source.append(line).append("\n");
|
474
|
+
}
|
475
|
+
buffer.close();
|
476
|
+
return source.toString();
|
477
|
+
}
|
478
|
+
|
479
|
+
/*************************************************************************************************
|
480
|
+
*
|
481
|
+
* Script Actions
|
482
|
+
*/
|
483
|
+
|
484
|
+
public static String getScriptFilename() {
|
485
|
+
return callScriptingContainerMethod(String.class, "getScriptFilename");
|
486
|
+
}
|
487
|
+
|
488
|
+
public static void setScriptFilename(String name) {
|
489
|
+
callScriptingContainerMethod(Void.class, "setScriptFilename", name);
|
490
|
+
}
|
491
|
+
|
492
|
+
public String execute() throws IOException {
|
493
|
+
Script.setScriptFilename(getClass().getClassLoader().getResource(name).getPath());
|
494
|
+
return Script.execute(getContents());
|
495
|
+
}
|
496
|
+
|
497
|
+
public static void callMethod(Object receiver, String methodName, Object[] args) {
|
498
|
+
// callScriptingContainerMethod(Void.class, "callMethod", receiver, methodName, args);
|
499
|
+
try {
|
500
|
+
Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Object[].class);
|
501
|
+
callMethodMethod.invoke(ruby, receiver, methodName, args);
|
502
|
+
} catch (NoSuchMethodException nsme) {
|
503
|
+
throw new RuntimeException(nsme);
|
504
|
+
} catch (IllegalAccessException iae) {
|
505
|
+
throw new RuntimeException(iae);
|
506
|
+
} catch (java.lang.reflect.InvocationTargetException ite) {
|
507
|
+
throw (RuntimeException)(ite.getCause());
|
508
|
+
}
|
509
|
+
}
|
510
|
+
|
511
|
+
public static void callMethod(Object object, String methodName, Object arg) {
|
512
|
+
callMethod(object, methodName, new Object[] { arg });
|
513
|
+
}
|
514
|
+
|
515
|
+
public static void callMethod(Object object, String methodName) {
|
516
|
+
callMethod(object, methodName, new Object[] {});
|
517
|
+
}
|
518
|
+
|
519
|
+
@SuppressWarnings("unchecked")
|
520
|
+
public static <T> T callMethod(Object receiver, String methodName, Object[] args, Class<T> returnType) {
|
521
|
+
// return callScriptingContainerMethod(returnType, "callMethod", receiver, methodName, args, returnType);
|
522
|
+
try {
|
523
|
+
Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Object[].class, Class.class);
|
524
|
+
return (T) callMethodMethod.invoke(ruby, receiver, methodName, args, returnType);
|
525
|
+
} catch (NoSuchMethodException nsme) {
|
526
|
+
throw new RuntimeException(nsme);
|
527
|
+
} catch (IllegalAccessException iae) {
|
528
|
+
throw new RuntimeException(iae);
|
529
|
+
} catch (java.lang.reflect.InvocationTargetException ite) {
|
530
|
+
throw (RuntimeException) ite.getCause();
|
531
|
+
}
|
532
|
+
}
|
533
|
+
|
534
|
+
public static <T> T callMethod(Object receiver, String methodName,
|
535
|
+
Object arg, Class<T> returnType) {
|
536
|
+
return callMethod(receiver, methodName, new Object[]{arg}, returnType);
|
537
|
+
}
|
538
|
+
|
539
|
+
public static <T> T callMethod(Object receiver, String methodName,
|
540
|
+
Class<T> returnType) {
|
541
|
+
return callMethod(receiver, methodName, new Object[]{}, returnType);
|
542
|
+
}
|
543
|
+
|
544
|
+
}
|
545
|
+
|