calatrava 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/.gitignore +9 -0
  2. data/.rvmrc +2 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +202 -0
  5. data/Plans.md +20 -0
  6. data/README.md +73 -0
  7. data/Rakefile +26 -0
  8. data/bin/calatrava +6 -0
  9. data/calatrava.gemspec +35 -0
  10. data/features/cli.feature +14 -0
  11. data/features/project.feature +48 -0
  12. data/features/step_definitions/template_steps.rb +8 -0
  13. data/features/support/env.rb +5 -0
  14. data/lib/calatrava/app.rb +30 -0
  15. data/lib/calatrava/manifest.rb +44 -0
  16. data/lib/calatrava/project.rb +218 -0
  17. data/lib/calatrava/resources_build_phase.rb +19 -0
  18. data/lib/calatrava/tasks/apache.rb +44 -0
  19. data/lib/calatrava/tasks/artifact.rb +24 -0
  20. data/lib/calatrava/tasks/assets.rb +6 -0
  21. data/lib/calatrava/tasks/automation.rb +38 -0
  22. data/lib/calatrava/tasks/bootstrap.rb +10 -0
  23. data/lib/calatrava/tasks/build.rb +1 -0
  24. data/lib/calatrava/tasks/configuration.rb +41 -0
  25. data/lib/calatrava/tasks/droid.rb +83 -0
  26. data/lib/calatrava/tasks/haml.rb +71 -0
  27. data/lib/calatrava/tasks/ios.rb +73 -0
  28. data/lib/calatrava/tasks/kernel.rb +52 -0
  29. data/lib/calatrava/tasks/precommit.rb +22 -0
  30. data/lib/calatrava/tasks/release.rb +17 -0
  31. data/lib/calatrava/tasks/shell.rb +17 -0
  32. data/lib/calatrava/tasks/web.rb +82 -0
  33. data/lib/calatrava/tasks.rb +93 -0
  34. data/lib/calatrava/template.rb +44 -0
  35. data/lib/calatrava/templates/.rvmrc.calatrava +2 -0
  36. data/lib/calatrava/templates/Gemfile.calatrava +4 -0
  37. data/lib/calatrava/templates/Rakefile +1 -0
  38. data/lib/calatrava/templates/assets/lib/ICanHaz.js +542 -0
  39. data/lib/calatrava/templates/assets/lib/underscore.js +1059 -0
  40. data/lib/calatrava/templates/assets/lib/zepto.js +1355 -0
  41. data/lib/calatrava/templates/build_env.sh +2 -0
  42. data/lib/calatrava/templates/config/environments.yml +17 -0
  43. data/lib/calatrava/templates/config/templates/env.coffee.erb +7 -0
  44. data/lib/calatrava/templates/config/templates/httpd.conf.erb +33 -0
  45. data/lib/calatrava/templates/droid/app/bridge.coffee +130 -0
  46. data/lib/calatrava/templates/droid/calatrava/ant/calatrava.xml +48 -0
  47. data/lib/calatrava/templates/droid/calatrava/calatrava-build.xml +91 -0
  48. data/lib/calatrava/templates/droid/calatrava/ivy.xml +8 -0
  49. data/lib/calatrava/templates/droid/calatrava/ivysettings.xml +12 -0
  50. data/lib/calatrava/templates/droid/calatrava/src/com/CALATRAVA_TMPL/AndroidManifest.xml.calatrava +20 -0
  51. data/lib/calatrava/templates/droid/calatrava/src/com/CALATRAVA_TMPL/ConversionForm.java.calatrava +27 -0
  52. data/lib/calatrava/templates/droid/calatrava/src/com/CALATRAVA_TMPL/Title.java.calatrava +23 -0
  53. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/CalatravaPage.java +13 -0
  54. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/AjaxRequestManager.java +166 -0
  55. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/AssetRepository.java +17 -0
  56. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/KernelBridge.java +25 -0
  57. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/Launcher.java +85 -0
  58. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/PageRegistry.java +225 -0
  59. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/RegisteredActivity.java +86 -0
  60. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/RequestLoader.java +31 -0
  61. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/bridge/RhinoService.java +212 -0
  62. data/lib/calatrava/templates/droid/calatrava/src/com/calatrava/shell/WebViewActivity.java +247 -0
  63. data/lib/calatrava/templates/droid/manifest.yml +1 -0
  64. data/lib/calatrava/templates/ios/Podfile.calatrava +5 -0
  65. data/lib/calatrava/templates/ios/manifest.yml +1 -0
  66. data/lib/calatrava/templates/ios/res/js/bridge.js +249 -0
  67. data/lib/calatrava/templates/ios/res/xibs/ProgressViewController.xib +334 -0
  68. data/lib/calatrava/templates/ios/res/xibs/WebViewController.xib +173 -0
  69. data/lib/calatrava/templates/ios/src/AppDelegate.h +8 -0
  70. data/lib/calatrava/templates/ios/src/AppDelegate.m +56 -0
  71. data/lib/calatrava/templates/ios/src/CALATRAVA_TMPL-Info.plist +45 -0
  72. data/lib/calatrava/templates/ios/src/CALATRAVA_TMPL-Prefix.pch +14 -0
  73. data/lib/calatrava/templates/ios/src/ConversionFormViewController.h +16 -0
  74. data/lib/calatrava/templates/ios/src/ConversionFormViewController.m +179 -0
  75. data/lib/calatrava/templates/ios/src/ConversionFormViewController.xib +357 -0
  76. data/lib/calatrava/templates/ios/src/en.lproj/InfoPlist.strings +2 -0
  77. data/lib/calatrava/templates/ios/src/main.m +10 -0
  78. data/lib/calatrava/templates/ios/test/AJAXConnectionTest.m +21 -0
  79. data/lib/calatrava/templates/ios/test/AppTests-Prefix.pch +8 -0
  80. data/lib/calatrava/templates/ios/test/CalatravaiOSTests-Info.plist +22 -0
  81. data/lib/calatrava/templates/ios/test/TWBridgePageRegistryTest.m +15 -0
  82. data/lib/calatrava/templates/ios/test/en.lproj/InfoPlist.strings +2 -0
  83. data/lib/calatrava/templates/kernel/.gitignore +1 -0
  84. data/lib/calatrava/templates/kernel/app/calatrava.coffee +8 -0
  85. data/lib/calatrava/templates/kernel/app/converter/controller.converter.coffee +50 -0
  86. data/lib/calatrava/templates/kernel/app/converter/init.converter.coffee +11 -0
  87. data/lib/calatrava/templates/kernel/app/pageHelper.coffee +17 -0
  88. data/lib/calatrava/templates/kernel/features/support/bridge.coffee +124 -0
  89. data/lib/calatrava/templates/kernel/features/support/spec_helper.js +49 -0
  90. data/lib/calatrava/templates/kernel/spec/converter/controller.converter.spec.coffee +37 -0
  91. data/lib/calatrava/templates/kernel/spec/environment.spec_helper.coffee +25 -0
  92. data/lib/calatrava/templates/kernel/spec/spec_helper.js +49 -0
  93. data/lib/calatrava/templates/kernel/spec/stubView.coffee +18 -0
  94. data/lib/calatrava/templates/kernel/watchr.rb +17 -0
  95. data/lib/calatrava/templates/package.json +20 -0
  96. data/lib/calatrava/templates/shell/layouts/single_page.haml +23 -0
  97. data/lib/calatrava/templates/shell/pages/converter/conversionForm.haml +12 -0
  98. data/lib/calatrava/templates/shell/pages/converter/page.conversionForm.coffee +42 -0
  99. data/lib/calatrava/templates/shell/shell.scss +1 -0
  100. data/lib/calatrava/templates/shell/support/shell.coffee +21 -0
  101. data/lib/calatrava/templates/web/apache/conf/mime.types +1357 -0
  102. data/lib/calatrava/templates/web/app/source/bridge.coffee +158 -0
  103. data/lib/calatrava/templates/web/app/source/init.coffee +14 -0
  104. data/lib/calatrava/templates/web/app/views/index.haml +18 -0
  105. data/lib/calatrava/templates/web/deploy/instance.sh +10 -0
  106. data/lib/calatrava/templates/web/manifest.yml +1 -0
  107. data/lib/calatrava/version.rb +3 -0
  108. data/lib/calatrava.rb +5 -0
  109. metadata +302 -0
@@ -0,0 +1,85 @@
1
+ package com.calatrava.bridge;
2
+
3
+ import android.app.Application;
4
+ import android.content.ComponentName;
5
+ import android.content.Context;
6
+ import android.content.Intent;
7
+ import android.content.ServiceConnection;
8
+ import android.os.IBinder;
9
+ import android.util.Log;
10
+
11
+ import java.io.IOException;
12
+ import java.io.BufferedReader;
13
+ import java.io.InputStreamReader;
14
+
15
+ public class Launcher {
16
+ private static String TAG = Launcher.class.getSimpleName();
17
+
18
+ private static String appName;
19
+ private static RhinoService rhino;
20
+ private static Context appContext;
21
+ private static Application application;
22
+ private static Runnable startUp;
23
+
24
+ static ServiceConnection connection = new ServiceConnection() {
25
+ public void onServiceConnected(ComponentName componentName, IBinder iBinder)
26
+ {
27
+ try
28
+ {
29
+ rhino = ((RhinoService.LocalBinder) iBinder).getService();
30
+ PageRegistry.setSharedRegistry(new PageRegistry(appName, appContext, application, rhino));
31
+ AjaxRequestManager.setSharedManager(new AjaxRequestManager(appContext, rhino));
32
+ initBridge();
33
+ startUp.run();
34
+ }
35
+ catch (Exception e)
36
+ {
37
+ Log.e(TAG, "Unable to start.", e);
38
+ }
39
+ }
40
+
41
+ public void onServiceDisconnected(ComponentName componentName) {
42
+
43
+ }
44
+ };
45
+
46
+ public static void launchKernel(String appName,
47
+ Context appContext,
48
+ Application application,
49
+ Runnable startUp) {
50
+ Launcher.appName = appName;
51
+ Launcher.appContext = appContext;
52
+ Launcher.application = application;
53
+ Launcher.startUp = startUp;
54
+
55
+ Intent serviceIntent = new Intent(appContext, RhinoService.class);
56
+ appContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE);
57
+ }
58
+
59
+ public static void launchFlow(String flow)
60
+ {
61
+ rhino.callJsFunction(flow);
62
+ }
63
+
64
+ private static void initBridge() {
65
+ AssetRepository assets = new AssetRepository(appContext);
66
+
67
+ try {
68
+ Log.d(TAG, "About to prep the rhino");
69
+ rhino.initRhino();
70
+
71
+ Log.d(TAG, "About to load and start kernel");
72
+ // Load all the application JS
73
+ KernelBridge bridge = new KernelBridge(assets, rhino);
74
+ BufferedReader loadFileReader = new BufferedReader(new InputStreamReader(appContext.getAssets().open("hybrid/load_file.text")), 8192);
75
+ String line = null;
76
+ while ((line = loadFileReader.readLine()) != null)
77
+ {
78
+ bridge.loadLibrary(line);
79
+ }
80
+
81
+ } catch (IOException e) {
82
+ Log.d(TAG, "LauncherActivity failed to start: " + e);
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,225 @@
1
+ package com.calatrava.bridge;
2
+
3
+ import android.app.Application;
4
+ import android.content.Context;
5
+ import android.content.Intent;
6
+ import android.content.ContextWrapper;
7
+ import android.net.Uri;
8
+ import android.util.Log;
9
+ import android.content.pm.PackageManager.NameNotFoundException;
10
+
11
+ import org.mozilla.javascript.ScriptableObject;
12
+
13
+ import com.calatrava.CalatravaPage;
14
+
15
+ import java.util.*;
16
+
17
+ import java.io.IOException;
18
+ import java.net.URISyntaxException;
19
+
20
+ import dalvik.system.DexFile;
21
+ import dalvik.system.PathClassLoader;
22
+ import dalvik.system.DexClassLoader;
23
+
24
+ import java.lang.annotation.Annotation;
25
+
26
+ public class PageRegistry {
27
+ public static String TAG = PageRegistry.class.getSimpleName();
28
+ private static PageRegistry sharedRegistry;
29
+
30
+ private Context appContext;
31
+ private RhinoService rhino;
32
+ private Map<String, Class<?>> pageFactories = new HashMap<String, Class<?>>();
33
+ private Map<String, RegisteredPage> registeredPages = new HashMap<String, RegisteredPage>();
34
+
35
+ public static PageRegistry sharedRegistry() {
36
+ return sharedRegistry;
37
+ }
38
+
39
+ public static void setSharedRegistry(PageRegistry shared) {
40
+ Log.d(TAG, "Set shared page registry");
41
+ sharedRegistry = shared;
42
+ }
43
+
44
+ public PageRegistry(String appName, Context appContext, Application app, RhinoService rhino)
45
+ throws IOException, URISyntaxException, ClassNotFoundException, NameNotFoundException
46
+ {
47
+ this.appContext = appContext;
48
+ this.rhino = rhino;
49
+
50
+ // Find all the logical page classes in the app
51
+ Log.d(TAG, "Searching for Calatrava pages in '" + appName + "'");
52
+ addPages(appName, appContext);
53
+ }
54
+
55
+ private void addPages(String packageName, Context context)
56
+ throws IOException, URISyntaxException, ClassNotFoundException, NameNotFoundException
57
+ {
58
+ String apkName = context.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;
59
+ DexFile dexFile = new DexFile(apkName);
60
+ PathClassLoader classLoader2 = new PathClassLoader(apkName, Thread.currentThread().getContextClassLoader());
61
+ DexClassLoader classLoader = new DexClassLoader(apkName, new ContextWrapper(context).getCacheDir().getAbsolutePath(), null, classLoader2);
62
+
63
+ Enumeration<String> entries = dexFile.entries();
64
+ while (entries.hasMoreElements())
65
+ {
66
+ String entry = entries.nextElement();
67
+ // only check items that exist in source package and not in libraries, etc.
68
+ if (entry.startsWith(packageName))
69
+ {
70
+ Class<?> entryClass = classLoader.loadClass(entry);
71
+ if (entryClass != null)
72
+ {
73
+ Annotation[] annotations = entryClass.getAnnotations();
74
+ for (Annotation annotation : annotations)
75
+ {
76
+ if (annotation instanceof CalatravaPage)
77
+ {
78
+ String pageName = ((CalatravaPage)annotation).name();
79
+ Log.d(TAG, "Registering Calatrava page: " + pageName);
80
+ pageFactories.put(pageName, entryClass);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ public void changePage(String target) {
89
+ Log.d(TAG, "changePage('" + target + "')");
90
+ Class activityClass = pageFactories.get(target);
91
+ Log.d(TAG, "Activity to be started: " + activityClass.getSimpleName());
92
+ appContext.startActivity(new Intent(appContext, activityClass));
93
+ }
94
+
95
+ public void displayWidget(String name, String options) {
96
+ appContext.sendBroadcast(new Intent("com.calatrava.widget").putExtra("name", name).putExtra("options", options));
97
+ }
98
+
99
+ public void displayDialog(String dialogName) {
100
+ appContext.sendBroadcast(new Intent("com.calatrava.dialog").putExtra("name", dialogName));
101
+ }
102
+
103
+ public void alert(String message) {
104
+ Log.d(TAG, "Broadcasting alert message: '" + message + "'");
105
+ appContext.sendBroadcast(new Intent("com.calatrava.alert").putExtra("message", message));
106
+ }
107
+
108
+ public void openUrl(String url) {
109
+ Intent browser = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
110
+ appContext.startActivity(browser);
111
+ }
112
+
113
+ public void track(String pageName, String channel, String eventName, Object variables, Object properties) {
114
+ }
115
+
116
+ public void startTimer(int timeout, final String timerId) {
117
+ final Timer timer = new Timer();
118
+ timer.schedule(new TimerTask() {
119
+ @Override
120
+ public void run() {
121
+ timer.cancel();
122
+ timer.purge();
123
+ rhino.callJsFunction("tw.bridge.timers.fireTimer", new String[] {timerId});
124
+ }
125
+ }, 1000 * timeout);
126
+ }
127
+
128
+ private HashMap<String, String> jsObjectToMap(ScriptableObject obj) {
129
+ HashMap<String, String> map = new HashMap<String, String>();
130
+ for (Object k : obj.getIds()) {
131
+ if (k instanceof String) {
132
+ map.put((String) k, ScriptableObject.getProperty(obj, (String) k).toString());
133
+ }
134
+ }
135
+ return map;
136
+ }
137
+
138
+ private void ensureRegisteredPage(String name, RegisteredActivity page) {
139
+ if (registeredPages.get(name) == null) {
140
+ registeredPages.put(name, new RegisteredPage(page));
141
+ } else if (page != null) {
142
+ registeredPages.get(name).setPage(page);
143
+ }
144
+ }
145
+
146
+ public void registerPage(String name, RegisteredActivity page) {
147
+ ensureRegisteredPage(name, page);
148
+ }
149
+
150
+ public void unregisterPage(String pageName) {
151
+ registeredPages.remove(pageName);
152
+ }
153
+
154
+ public String getValueForField(String page, String field) {
155
+ Log.d(TAG, "Requesting field '" + field + "' from page '" + page + "'");
156
+ ensureRegisteredPage(page, null);
157
+ return registeredPages.get(page).getFieldValue(field);
158
+ }
159
+
160
+ public void renderPage(String page, String renderJson) {
161
+ Log.d(TAG, "renderPage: '" + page + "' Response object: " + renderJson);
162
+
163
+ ensureRegisteredPage(page, null);
164
+ registeredPages.get(page).render(renderJson);
165
+ }
166
+
167
+ public void pageOffscreen(String page) {
168
+ ensureRegisteredPage(page, null);
169
+ registeredPages.get(page).pageOffscreen();
170
+ }
171
+
172
+ public void pageOnscreen(String page) {
173
+ ensureRegisteredPage(page, null);
174
+ registeredPages.get(page).pageOnscreen();
175
+ }
176
+
177
+ private class RegisteredPage {
178
+ private RegisteredActivity activity;
179
+ List<String> pendingRenders = new ArrayList<String>();
180
+ boolean onScreen = false;
181
+
182
+ private RegisteredPage(RegisteredActivity activity) {
183
+ this.activity = activity;
184
+ }
185
+
186
+ public RegisteredActivity getPage() {
187
+ return activity;
188
+ }
189
+
190
+ public void setPage(RegisteredActivity page) {
191
+ this.activity = page;
192
+ }
193
+
194
+ public void render(String renderJson) {
195
+ if (activity != null && onScreen) {
196
+ activity.render(renderJson);
197
+ } else {
198
+ pendingRenders.add(renderJson);
199
+ }
200
+ }
201
+
202
+ public String getFieldValue(String field) {
203
+ if (activity != null) {
204
+ return activity.getFieldValue(field);
205
+ } else {
206
+ return "";
207
+ }
208
+ }
209
+
210
+ public void pageOffscreen() {
211
+ onScreen = false;
212
+ }
213
+
214
+ public void pageOnscreen() {
215
+ onScreen = true;
216
+
217
+ for (String pendingRender : pendingRenders) {
218
+ Log.d(TAG, "Pending activity for: " + pendingRender);
219
+
220
+ activity.render(pendingRender);
221
+ }
222
+ pendingRenders.clear();
223
+ }
224
+ }
225
+ }
@@ -0,0 +1,86 @@
1
+ package com.calatrava.bridge;
2
+
3
+ import android.app.Activity;
4
+ import android.app.AlertDialog;
5
+ import android.content.*;
6
+ import android.os.Bundle;
7
+ import android.os.IBinder;
8
+ import android.util.Log;
9
+
10
+ public abstract class RegisteredActivity extends Activity {
11
+ private String TAG = RegisteredActivity.class.getSimpleName();
12
+
13
+ private RhinoService rhino;
14
+ private RequestLoader spinner = new RequestLoader(this);
15
+ private ServiceConnection connection = new ServiceConnection() {
16
+ public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
17
+ rhino = ((RhinoService.LocalBinder) iBinder).getService();
18
+ RegisteredActivity.this.onRhinoConnected(rhino);
19
+ }
20
+
21
+ public void onServiceDisconnected(ComponentName componentName) {
22
+
23
+ }
24
+ };
25
+
26
+ private BroadcastReceiver receiver = new BroadcastReceiver() {
27
+ @Override
28
+ public void onReceive(Context context, Intent intent) {
29
+ Log.d(TAG, "Received broadcast");
30
+ if (intent.getAction().endsWith("start")) {
31
+ spinner.onLoadingStart();
32
+ } else if (intent.getAction().endsWith("finish")) {
33
+ spinner.onLoadingFinish();
34
+ } else {
35
+ AlertDialog.Builder builder = new AlertDialog.Builder(RegisteredActivity.this);
36
+ builder.setMessage(intent.getExtras().getString("message"))
37
+ .setCancelable(false)
38
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
39
+ @Override
40
+ public void onClick(DialogInterface dialogInterface, int i) {
41
+ dialogInterface.dismiss();
42
+ }
43
+ });
44
+ AlertDialog dialog = builder.create();
45
+ dialog.show();
46
+ }
47
+ }
48
+ };
49
+
50
+ @Override
51
+ protected void onCreate(Bundle availableData) {
52
+ super.onCreate(availableData);
53
+ Intent serviceIntent = new Intent(this, RhinoService.class);
54
+ bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE);
55
+ }
56
+
57
+ @Override
58
+ protected void onResume() {
59
+ super.onResume();
60
+ registerReceiver(receiver, new IntentFilter("com.calatrava.ajax.start"));
61
+ registerReceiver(receiver, new IntentFilter("com.calatrava.ajax.finish"));
62
+ registerReceiver(receiver, new IntentFilter("com.calatrava.alert"));
63
+ }
64
+
65
+ @Override
66
+ protected void onPause() {
67
+ super.onPause();
68
+ unregisterReceiver(receiver);
69
+ }
70
+
71
+ @Override
72
+ public void onDestroy() {
73
+ super.onDestroy();
74
+ unbindService(connection);
75
+ }
76
+
77
+ public void invokeWidgetCallback(String...args) {
78
+ rhino.callJsFunction("tw.bridge.widgets.invokeCallback", args);
79
+ }
80
+
81
+ protected abstract void onRhinoConnected(RhinoService rhino);
82
+
83
+ public abstract String getFieldValue(String field);
84
+
85
+ public abstract void render(final String json);
86
+ }
@@ -0,0 +1,31 @@
1
+ package com.calatrava.bridge;
2
+
3
+ import android.app.Activity;
4
+ import android.app.ActivityManager;
5
+ import android.app.ProgressDialog;
6
+ import android.content.Context;
7
+ import android.util.Log;
8
+
9
+ public class RequestLoader {
10
+ private String TAG = RequestLoader.class.getSimpleName();
11
+
12
+ private ProgressDialog dialog;
13
+ private Activity parent;
14
+
15
+ public RequestLoader(Activity parent) {
16
+ this.parent = parent;
17
+ }
18
+
19
+ public void onLoadingStart() {
20
+ Log.d(TAG, "About to create loader");
21
+ dialog = new ProgressDialog(parent);
22
+ dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
23
+ dialog.setMessage("Loading...");
24
+ dialog.setCancelable(false);
25
+ dialog.show();
26
+ }
27
+
28
+ public void onLoadingFinish() {
29
+ dialog.hide();
30
+ }
31
+ }
@@ -0,0 +1,212 @@
1
+ package com.calatrava.bridge;
2
+
3
+ import android.app.Service;
4
+ import android.content.Intent;
5
+ import android.os.*;
6
+ import android.util.Log;
7
+ import org.mozilla.javascript.Context;
8
+ import org.mozilla.javascript.Scriptable;
9
+ import org.mozilla.javascript.ScriptableObject;
10
+
11
+ import java.io.IOException;
12
+ import java.io.Reader;
13
+ import java.lang.String;
14
+ import java.lang.ThreadGroup;
15
+ import java.util.concurrent.CountDownLatch;
16
+
17
+ public class RhinoService extends Service {
18
+ public static String TAG = RhinoService.class.getSimpleName();
19
+
20
+ private Scriptable mScope;
21
+ private JSEvalThread evaller = new JSEvalThread();
22
+
23
+ private final IBinder mBinder = new LocalBinder();
24
+
25
+ CountDownLatch countDownLatch = new CountDownLatch(1);
26
+
27
+ @Override
28
+ public IBinder onBind(Intent intent) {
29
+ return mBinder;
30
+ }
31
+
32
+ @Override
33
+ public void onCreate() {
34
+ super.onCreate();
35
+ Log.d(TAG, "RhinoService created.");
36
+ }
37
+
38
+ public void initRhino() {
39
+ Context ctxt = enterContext();
40
+ try {
41
+ mScope = ctxt.initStandardObjects();
42
+
43
+ Object wrappedRegistry = Context.javaToJS(PageRegistry.sharedRegistry(), mScope);
44
+ ScriptableObject.putProperty(mScope, "pageRegistry", wrappedRegistry);
45
+
46
+ Object wrappedAjaxRequestManagerRegistry = Context.javaToJS(AjaxRequestManager.sharedManager(), mScope);
47
+ ScriptableObject.putProperty(mScope, "ajaxRequestManagerRegistry", wrappedAjaxRequestManagerRegistry);
48
+
49
+ evaller.start();
50
+ try {
51
+ countDownLatch.await();
52
+ } catch (InterruptedException e) {
53
+ Log.d(TAG, "Interrupted Exception when waiting for JSEvalThread");
54
+ e.printStackTrace();
55
+ }
56
+ } finally {
57
+ Context.exit();
58
+ }
59
+ }
60
+
61
+ private Context enterContext() {
62
+ Context ctxt = Context.enter();
63
+ // No pre-compilation
64
+ ctxt.setOptimizationLevel(-1);
65
+ return ctxt;
66
+ }
67
+
68
+ @Override
69
+ public void onDestroy() {
70
+ Log.d(TAG, "RhinoService destroyed.");
71
+ super.onDestroy();
72
+ }
73
+
74
+ public void load(Reader source, String name) {
75
+ evaller.load(source, name);
76
+ }
77
+
78
+ public void triggerEvent(String page, String eventId, String[] extraArgs) {
79
+ evaller.triggerEvent(page, eventId, extraArgs);
80
+ }
81
+
82
+ public void invokeSuccessCallback(String requestId, String response) {
83
+ evaller.ajaxSuccessfulResponse(requestId, response);
84
+ }
85
+
86
+ public void invokeFailureCallback(String requestId, int statusCode, String responseBody) {
87
+ evaller.ajaxFailureResponse(requestId, statusCode, responseBody);
88
+ }
89
+
90
+ public void callJsFunction(String function) {
91
+ evaller.callJsFunction(function);
92
+ }
93
+
94
+ public void callJsFunction(String function, String[] args) {
95
+ evaller.callJsFunction(function, args);
96
+ }
97
+
98
+ public class LocalBinder extends Binder {
99
+ public RhinoService getService() {
100
+ return RhinoService.this;
101
+ }
102
+ }
103
+
104
+ class JSEvalThread extends Thread {
105
+ private Handler handler;
106
+ private Context ctxt;
107
+
108
+ public JSEvalThread() {
109
+ super(null, null, "js eval thread", 32768);
110
+ }
111
+
112
+ public void load(final Reader source, final String name) {
113
+ handler.post(new Runnable() {
114
+ @Override
115
+ public void run() {
116
+ try {
117
+ Log.d(TAG, "Loading file: '" + name + "'");
118
+ ctxt.evaluateReader(mScope, source, name, 0, null);
119
+ } catch (IOException e) {
120
+ Log.e(TAG, "Error loading file: '" + name + "'", e);
121
+ }
122
+ }
123
+ });
124
+ }
125
+
126
+ public void callJsFunction(String function) {
127
+ String js = "{0}();"
128
+ .replace("{0}", function);
129
+ dispatchJs(js);
130
+ }
131
+
132
+ public void callJsFunction(String function, String[] args) {
133
+ StringBuilder sb = new StringBuilder("");
134
+ boolean first = true;
135
+ for (String arg : args) {
136
+ if (!first) {
137
+ sb.append(",");
138
+ }
139
+ first = false;
140
+ sb.append("'" + arg + "'");
141
+ }
142
+
143
+ String js = "{0}({1});"
144
+ .replace("{0}", function)
145
+ .replace("{1}", sb.toString());
146
+
147
+ Log.d(TAG, "Dispatching: " + js);
148
+
149
+ dispatchJs(js);
150
+ }
151
+
152
+ public void triggerEvent(String page, String eventId, String[] extraArgs) {
153
+ StringBuilder sb = new StringBuilder("");
154
+ for (String arg : extraArgs) {
155
+ sb.append(", '");
156
+ sb.append(arg);
157
+ sb.append("'");
158
+ }
159
+ String js = "tw.bridge.dispatchEvent('{0}', '{1}'{2});"
160
+ .replace("{0}", page)
161
+ .replace("{1}", eventId)
162
+ .replace("{2}", sb.toString());
163
+
164
+ Log.d(TAG, "Dispatching: " + js);
165
+
166
+ dispatchJs(js);
167
+ }
168
+
169
+ public void ajaxSuccessfulResponse(String requestId, String json) {
170
+ String js = "tw.bridge.requests.successfulResponse('{0}', '{1}');"
171
+ .replace("{0}", requestId)
172
+ .replace("{1}", json);
173
+ dispatchJs(js);
174
+ }
175
+
176
+ public void ajaxFailureResponse(String requestId, int statusCode, String responseBody) {
177
+ String js = "tw.bridge.requests.failureResponse('{0}', {1}, '{2}');"
178
+ .replace("{0}", requestId)
179
+ .replace("{1}", Integer.toString(statusCode))
180
+ .replace("{2}", responseBody);
181
+ dispatchJs(js);
182
+ }
183
+
184
+ public void run() {
185
+ Looper.prepare();
186
+ ctxt = enterContext();
187
+
188
+ try {
189
+ handler = new Handler();
190
+ countDownLatch.countDown();
191
+ Looper.loop();
192
+ }
193
+ finally {
194
+ Context.exit();
195
+ }
196
+ }
197
+
198
+ private void dispatchJs(final String js) {
199
+ handler.post(new Runnable() {
200
+ @Override
201
+ public void run() {
202
+ eval(js);
203
+ }
204
+ });
205
+ }
206
+
207
+ private void eval(String jsCode) {
208
+ ctxt.evaluateString(mScope, jsCode, "<Bridge>", 1, null);
209
+ }
210
+
211
+ }
212
+ }