ruboto 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|