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.
Files changed (67) hide show
  1. data/COPYING +19 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +21 -0
  4. data/README.md +293 -0
  5. data/Rakefile +114 -0
  6. data/assets/Rakefile +386 -0
  7. data/assets/res/drawable-hdpi/icon.png +0 -0
  8. data/assets/res/drawable-ldpi/icon.png +0 -0
  9. data/assets/res/drawable-mdpi/icon.png +0 -0
  10. data/assets/res/layout/get_ruboto_core.xml +25 -0
  11. data/assets/samples/sample_activity.rb +21 -0
  12. data/assets/samples/sample_activity_test.rb +21 -0
  13. data/assets/samples/sample_broadcast_receiver.rb +6 -0
  14. data/assets/samples/sample_broadcast_receiver_test.rb +1 -0
  15. data/assets/samples/sample_service.rb +14 -0
  16. data/assets/samples/sample_service_test.rb +1 -0
  17. data/assets/src/InheritingActivity.java +195 -0
  18. data/assets/src/InheritingBroadcastReceiver.java +27 -0
  19. data/assets/src/InheritingClass.java +19 -0
  20. data/assets/src/InheritingService.java +9 -0
  21. data/assets/src/RubotoActivity.java +111 -0
  22. data/assets/src/RubotoBroadcastReceiver.java +51 -0
  23. data/assets/src/RubotoService.java +61 -0
  24. data/assets/src/org/ruboto/RubotoDialog.java +11 -0
  25. data/assets/src/org/ruboto/Script.java +545 -0
  26. data/assets/src/org/ruboto/test/ActivityTest.java +63 -0
  27. data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +124 -0
  28. data/assets/src/ruboto.rb +621 -0
  29. data/assets/test/assets/scripts/test_helper.rb +13 -0
  30. data/bin/ruboto +5 -0
  31. data/lib/java_class_gen/InheritingClass.java.erb +10 -0
  32. data/lib/java_class_gen/android_api.xml +1 -0
  33. data/lib/ruboto.rb +16 -0
  34. data/lib/ruboto/api.rb +21 -0
  35. data/lib/ruboto/commands/base.rb +392 -0
  36. data/lib/ruboto/core_ext/array.rb +6 -0
  37. data/lib/ruboto/core_ext/object.rb +10 -0
  38. data/lib/ruboto/util/asset_copier.rb +27 -0
  39. data/lib/ruboto/util/build.rb +201 -0
  40. data/lib/ruboto/util/code_formatting.rb +22 -0
  41. data/lib/ruboto/util/log_action.rb +20 -0
  42. data/lib/ruboto/util/main_fix.rb +13 -0
  43. data/lib/ruboto/util/objectspace.rb +8 -0
  44. data/lib/ruboto/util/scan_in_api.rb +40 -0
  45. data/lib/ruboto/util/update.rb +420 -0
  46. data/lib/ruboto/util/verify.rb +87 -0
  47. data/lib/ruboto/util/xml_element.rb +200 -0
  48. data/lib/ruboto/version.rb +3 -0
  49. data/test/activity/image_button_activity.rb +21 -0
  50. data/test/activity/image_button_activity_test.rb +21 -0
  51. data/test/activity/image_button_and_button_activity.rb +24 -0
  52. data/test/activity/image_button_and_button_activity_test.rb +27 -0
  53. data/test/activity/option_menu_activity.rb +21 -0
  54. data/test/activity/option_menu_activity_test.rb +20 -0
  55. data/test/activity/stack_activity.rb +21 -0
  56. data/test/activity/stack_activity_test.rb +23 -0
  57. data/test/app_test_methods.rb +41 -0
  58. data/test/minimal_app_test.rb +23 -0
  59. data/test/rake_test.rb +40 -0
  60. data/test/ruboto_gen_test.rb +32 -0
  61. data/test/ruboto_gen_with_psych_test.rb +16 -0
  62. data/test/ruboto_update_test.rb +5 -0
  63. data/test/ruboto_update_with_psych_test.rb +18 -0
  64. data/test/service_test.rb +49 -0
  65. data/test/test_helper.rb +177 -0
  66. data/test/update_test_methods.rb +33 -0
  67. metadata +157 -0
@@ -0,0 +1,63 @@
1
+ package org.ruboto.test;
2
+
3
+ import android.app.Activity;
4
+ import android.app.ProgressDialog;
5
+ import android.test.ActivityInstrumentationTestCase2;
6
+ import android.util.Log;
7
+ import java.io.BufferedReader;
8
+ import java.io.FileReader;
9
+ import java.io.InputStream;
10
+ import java.io.InputStreamReader;
11
+ import java.io.IOException;
12
+ import junit.framework.AssertionFailedError;
13
+ import junit.framework.Test;
14
+ import junit.framework.TestResult;
15
+ import junit.framework.TestSuite;
16
+ import org.ruboto.Script;
17
+
18
+ public class ActivityTest extends ActivityInstrumentationTestCase2 {
19
+ private final Object setup;
20
+ private final Object block;
21
+ private final String filename;
22
+
23
+ public ActivityTest(Class activityClass, String filename, Object setup, String name, Object block) {
24
+ super(activityClass.getPackage().getName(), activityClass);
25
+ this.filename = filename;
26
+ this.setup = setup;
27
+ setName(filename + "#" + name);
28
+ this.block = block;
29
+ Log.i(getClass().getName(), "Instance: " + getName());
30
+ }
31
+
32
+ public void runTest() throws Exception {
33
+ Log.i(getClass().getName(), "runTest");
34
+ Log.i(getClass().getName(), "runTest: " + getName());
35
+ if (Script.setUpJRuby(getActivity())) {
36
+ Log.i(getClass().getName(), "ruby ok");
37
+ try {
38
+ final Activity activity = getActivity();
39
+ Log.i(getClass().getName(), "activity ok");
40
+ runTestOnUiThread(new Runnable() {
41
+ public void run() {
42
+ String oldFile = Script.getScriptFilename();
43
+
44
+ Log.i(getClass().getName(), "calling setup");
45
+ Script.setScriptFilename(filename);
46
+ Script.callMethod(setup, "call", activity);
47
+ Log.i(getClass().getName(), "setup ok");
48
+
49
+ Script.setScriptFilename(filename);
50
+ Script.callMethod(block, "call", activity);
51
+ Script.setScriptFilename(oldFile);
52
+ }
53
+ });
54
+ } catch (Throwable t) {
55
+ throw new AssertionFailedError(t.getMessage() != null ? t.getMessage() : t.getClass().getName());
56
+ }
57
+ Log.i(getClass().getName(), "runTest ok");
58
+ } else {
59
+ throw new AssertionFailedError("Ruboto Core platform is missing.");
60
+ }
61
+ }
62
+
63
+ }
@@ -0,0 +1,124 @@
1
+ package org.ruboto.test;
2
+
3
+ import android.test.ActivityInstrumentationTestCase2;
4
+ import android.util.Log;
5
+ import java.io.BufferedReader;
6
+ import java.io.File;
7
+ import java.io.FileInputStream;
8
+ import java.io.InputStream;
9
+ import java.io.InputStreamReader;
10
+ import java.io.IOException;
11
+ import java.io.UnsupportedEncodingException;
12
+ import java.net.JarURLConnection;
13
+ import java.net.URL;
14
+ import java.net.URLDecoder;
15
+ import java.util.ArrayList;
16
+ import java.util.Arrays;
17
+ import java.util.Collections;
18
+ import java.util.Enumeration;
19
+ import java.util.jar.JarFile;
20
+ import java.util.jar.JarEntry;
21
+ import java.util.List;
22
+ import junit.framework.Test;
23
+ import junit.framework.TestCase;
24
+ import junit.framework.TestSuite;
25
+ import org.ruboto.Script;
26
+
27
+ public class InstrumentationTestRunner extends android.test.InstrumentationTestRunner {
28
+ private Class activityClass;
29
+ private Object setup;
30
+ private TestSuite suite;
31
+
32
+ public TestSuite getAllTests() {
33
+ Log.i(getClass().getName(), "Finding test scripts");
34
+ suite = new TestSuite("Sweet");
35
+
36
+ try {
37
+ if (Script.setUpJRuby(getTargetContext())) {
38
+ Script.defineGlobalVariable("$runner", this);
39
+ Script.defineGlobalVariable("$test", this);
40
+ Script.defineGlobalVariable("$suite", suite);
41
+
42
+ // TODO(uwe): Why doesn't this work?
43
+ // Script.copyScriptsIfNeeded(getContext());
44
+
45
+ loadScript("test_helper.rb");
46
+
47
+ // TODO(uwe): Why doesn't this work?
48
+ // String[] scripts = new File(Script.scriptsDirName(getContext())).list();
49
+
50
+ String[] scripts = getContext().getResources().getAssets().list("scripts");
51
+ for (String f : scripts) {
52
+ if (f.equals("test_helper.rb")) continue;
53
+ Log.i(getClass().getName(), "Found script: " + f);
54
+ loadScript(f);
55
+ }
56
+ } else {
57
+ addError(suite, new RuntimeException("Ruboto Core platform is missing"));
58
+ }
59
+ } catch (IOException e) {
60
+ addError(suite, e);
61
+ } catch (RuntimeException e) {
62
+ addError(suite, e);
63
+ }
64
+ return suite;
65
+ }
66
+
67
+ public void activity(Class activityClass) {
68
+ this.activityClass = activityClass;
69
+ }
70
+
71
+ public void setup(Object block) {
72
+ this.setup = block;
73
+ }
74
+
75
+ public void test(String name, Object block) {
76
+ if (android.os.Build.VERSION.SDK_INT <= 8) {
77
+ name ="runTest";
78
+ }
79
+ Test test = new ActivityTest(activityClass, Script.getScriptFilename(), setup, name, block);
80
+ suite.addTest(test);
81
+ Log.d(getClass().getName(), "Made test instance: " + test);
82
+ }
83
+
84
+ private void addError(TestSuite suite, Throwable t) {
85
+ Throwable cause = t;
86
+ while(cause != null) {
87
+ Log.e(getClass().getName(), "Exception loading tests: " + cause);
88
+ t = cause;
89
+ cause = t.getCause();
90
+ }
91
+ final Throwable rootCause = t;
92
+ rootCause.printStackTrace();
93
+ suite.addTest(new TestCase(t.getMessage()) {
94
+ public void runTest() throws java.lang.Throwable {
95
+ throw rootCause;
96
+ }
97
+ });
98
+ }
99
+
100
+ private void loadScript(String f) throws IOException {
101
+ // TODO(uwe): Why doesn't this work?
102
+ // InputStream is = new FileInputStream(Script.scriptsDirName(getContext()) + "/" + f);
103
+
104
+ InputStream is = getContext().getResources().getAssets().open("scripts/" + f);
105
+ BufferedReader buffer = new BufferedReader(new InputStreamReader(is));
106
+ StringBuilder source = new StringBuilder();
107
+ while (true) {
108
+ String line = buffer.readLine();
109
+ if (line == null) break;
110
+ source.append(line).append("\n");
111
+ }
112
+ buffer.close();
113
+
114
+ Log.d(getClass().getName(), "Loading test script: " + f);
115
+ String oldFilename = Script.getScriptFilename();
116
+ Script.setScriptFilename(f);
117
+ Script.put("$script_code", source.toString());
118
+ Script.setScriptFilename(f);
119
+ Script.execute("$test.instance_eval($script_code)");
120
+ Script.setScriptFilename(oldFilename);
121
+ Log.d(getClass().getName(), "Test script " + f + " loaded");
122
+ }
123
+
124
+ }
@@ -0,0 +1,621 @@
1
+ #######################################################
2
+ #
3
+ # ruboto.rb
4
+ #
5
+ # - Wrapper for using RubotoActivity, RubotoService, and
6
+ # RubotoBroadcastReceiver.
7
+ # - Provides interface for generating UI elements.
8
+ # - Imports and configures callback classes.
9
+ #
10
+ #######################################################
11
+
12
+ require 'ruboto/version'
13
+ $RUBOTO_VERSION = 9
14
+
15
+ def confirm_ruboto_version(required_version, exact=true)
16
+ raise "requires $RUBOTO_VERSION=#{required_version} or greater, current version #{$RUBOTO_VERSION}" if $RUBOTO_VERSION < required_version and not exact
17
+ raise "requires $RUBOTO_VERSION=#{required_version}, current version #{$RUBOTO_VERSION}" if $RUBOTO_VERSION != required_version and exact
18
+ end
19
+
20
+ require 'java'
21
+
22
+ $package_name = ($activity || $service || $broadcast_receiver).package_name
23
+ $package = eval("Java::#{$package_name}")
24
+
25
+ # Create convenience method for top-level android package so we do not need to prefix with 'Java::'.
26
+ module Kernel
27
+ def android
28
+ JavaUtilities.get_package_module_dot_format('android')
29
+ end
30
+ end
31
+
32
+ java_import "android.R"
33
+
34
+ module Ruboto
35
+ java_import "#{$package_name}.R"
36
+ begin
37
+ Id = JavaUtilities.get_proxy_class("#{$package_name}.R$id")
38
+ rescue NameError
39
+ Java::android.util.Log.d "RUBOTO", "no R$id"
40
+ end
41
+ end
42
+ AndroidIds = JavaUtilities.get_proxy_class("android.R$id")
43
+
44
+ class Object
45
+ def with_large_stack(opts = {}, &block)
46
+ opts = {:size => opts} if opts.is_a? Integer
47
+ opts = {:name => 'Block with large stack'}.update(opts)
48
+ exception = nil
49
+ result = nil
50
+ t = Thread.with_large_stack(opts, &proc{result = block.call rescue exception = $!})
51
+ t.join
52
+ raise exception if exception
53
+ result
54
+ end
55
+ end
56
+
57
+ class Thread
58
+ def self.with_large_stack(opts = {}, &block)
59
+ opts = {:size => opts} if opts.is_a? Integer
60
+ stack_size_kb = opts.delete(:size) || 64
61
+ name = opts.delete(:name) || "Thread with large stack"
62
+ raise "Unknown option(s): #{opts.inspect}" unless opts.empty?
63
+ t = java.lang.Thread.new(nil, block, name, stack_size_kb * 1024)
64
+ t.start
65
+ t
66
+ end
67
+ end
68
+
69
+ #############################################################################
70
+ #
71
+ # Activity
72
+ #
73
+
74
+ def setup_activity
75
+ java_import "android.app.Activity"
76
+
77
+ Activity.class_eval do
78
+ def start_ruboto_dialog(remote_variable, theme=R.style::Theme_Dialog, &block)
79
+ start_ruboto_activity(remote_variable, RubotoDialog, theme, &block)
80
+ end
81
+
82
+ def start_ruboto_activity(remote_variable, klass=RubotoActivity, theme=nil, &block)
83
+ $activity_init_block = block
84
+
85
+ if @initialized or (self == $activity && !$activity.kind_of?(RubotoActivity))
86
+ b = Java::android.os.Bundle.new
87
+ b.putInt("Theme", theme) if theme
88
+ b.putString("Remote Variable", remote_variable)
89
+ b.putBoolean("Define Remote Variable", true)
90
+ b.putString("Initialize Script", "#{remote_variable}.initialize_activity")
91
+
92
+ i = Java::android.content.Intent.new
93
+ i.setClass self, klass.java_class
94
+ i.putExtra("RubotoActivity Config", b)
95
+
96
+ self.startActivity i
97
+ else
98
+ instance_eval "#{remote_variable}=self"
99
+ setRemoteVariable remote_variable
100
+ initialize_activity
101
+ on_create nil
102
+ end
103
+
104
+ self
105
+ end
106
+
107
+ #plugin
108
+ def toast(text, duration=5000)
109
+ Java::android.widget.Toast.makeText(self, text, duration).show
110
+ end
111
+
112
+ #plugin
113
+ def toast_result(result, success, failure, duration=5000)
114
+ toast(result ? success : failure, duration)
115
+ end
116
+ end
117
+ end
118
+
119
+ #############################################################################
120
+ #
121
+ # Configure a class to work with handlers
122
+ #
123
+
124
+ def ruboto_allow_handlers(klass)
125
+ klass.class_eval do
126
+ def method_missing(name, *args, &block)
127
+ if name.to_s =~ /^handle_(.*)/ and (const = self.class.const_get("CB_#{$1.upcase}"))
128
+ setCallbackProc(const, block)
129
+ self
130
+ else
131
+ super
132
+ end
133
+ end
134
+
135
+ def respond_to?(name)
136
+ return true if name.to_s =~ /^handle_(.*)/ and self.class.const_get("CB_#{$1.upcase}")
137
+ super
138
+ end
139
+
140
+ def initialize_handlers(&block)
141
+ instance_eval &block
142
+ self
143
+ end
144
+ end
145
+ klass
146
+ end
147
+
148
+ #############################################################################
149
+ #
150
+ # Activity Subclass Setup
151
+ #
152
+
153
+ def ruboto_configure_activity(klass)
154
+ klass.class_eval do
155
+ #
156
+ # Initialize
157
+ #
158
+
159
+ def initialize_activity()
160
+ instance_eval &$activity_init_block
161
+ @initialized = true
162
+ self
163
+ end
164
+
165
+ def handle_finish_create &block
166
+ @finish_create_block = block
167
+ end
168
+
169
+ def setup_content &block
170
+ @content_view_block = block
171
+ end
172
+
173
+ def on_create(bundle)
174
+ @view_parent = nil
175
+ setContentView(instance_eval &@content_view_block) if @content_view_block
176
+ instance_eval { @finish_create_block.call } if @finish_create_block
177
+ end
178
+
179
+ #
180
+ # Option Menus
181
+ #
182
+
183
+ def add_menu title, icon=nil, &block
184
+ mi = @menu.add(title)
185
+ mi.setIcon(icon) if icon
186
+ mi.class.class_eval { attr_accessor :on_click }
187
+ mi.on_click = block
188
+
189
+ # Seems to be needed or the block might get cleaned up
190
+ @all_menu_items = [] unless @all_menu_items
191
+ @all_menu_items << mi
192
+ end
193
+
194
+ def handle_create_options_menu &block
195
+ p = Proc.new do |*args|
196
+ @menu = args[0]
197
+ instance_eval { block.call(*args) } if block
198
+ end
199
+ setCallbackProc(self.class.const_get("CB_CREATE_OPTIONS_MENU"), p)
200
+
201
+ p = Proc.new do |num, menu_item|
202
+ # handles a problem where this is called for context items
203
+ # TODO(uwe): JRUBY-5866 JRuby can't access nested Java class if the class is called 'id'
204
+ # TODO(uwe): Remove check for SDK version when we stop supporting api level < 11
205
+ unless @just_processed_context_item == menu_item || (android.os.Build::VERSION::SDK_INT >= 11 && menu_item.item_id == AndroidIds.home)
206
+ instance_eval &(menu_item.on_click)
207
+ @just_processed_context_item = nil
208
+ true
209
+ else
210
+ false
211
+ end
212
+ end
213
+ setCallbackProc(self.class.const_get("CB_MENU_ITEM_SELECTED"), p)
214
+ end
215
+
216
+ #
217
+ # Context Menus
218
+ #
219
+
220
+ def add_context_menu title, &block
221
+ mi = @context_menu.add(title)
222
+ mi.class.class_eval { attr_accessor :on_click }
223
+ mi.on_click = block
224
+
225
+ # Seems to be needed or the block might get cleaned up
226
+ @all_menu_items = [] unless @all_menu_items
227
+ @all_menu_items << mi
228
+ end
229
+
230
+ def handle_create_context_menu &block
231
+ p = Proc.new do |*args|
232
+ @context_menu = args[0]
233
+ instance_eval { block.call(*args) } if block
234
+ end
235
+ setCallbackProc(self.class.const_get("CB_CREATE_CONTEXT_MENU"), p)
236
+
237
+ p = Proc.new do |menu_item|
238
+ if menu_item.on_click
239
+ arg = menu_item
240
+ begin
241
+ arg = menu_item.getMenuInfo.position
242
+ rescue
243
+ end
244
+ instance_eval { menu_item.on_click.call(arg) }
245
+ @just_processed_context_item = menu_item
246
+ true
247
+ else
248
+ false
249
+ end
250
+ end
251
+ setCallbackProc(self.class.const_get("CB_CONTEXT_ITEM_SELECTED"), p)
252
+ end
253
+ end
254
+
255
+ ruboto_allow_handlers(klass)
256
+ end
257
+
258
+ #############################################################################
259
+ #
260
+ # Ruboto Set up for all app types (Activity, Service, BroadcastReceiver)
261
+ #
262
+
263
+ def ruboto_setup(klass, init_method = true)
264
+ # Setup ability to handle callbacks
265
+ ruboto_allow_handlers(klass)
266
+
267
+ if init_method
268
+ klass.class_eval do
269
+ eval %Q{
270
+ def handle_create(&block)
271
+ instance_exec &block
272
+ #{klass == Java::org.ruboto.RubotoActivity ? "on_create(nil)" : ""}
273
+ end
274
+ }
275
+ end
276
+ end
277
+ end
278
+
279
+ #############################################################################
280
+ #
281
+ # RubotoActivity View Generation
282
+ #
283
+
284
+ def ruboto_import_widgets(*widgets)
285
+ widgets.each { |i| ruboto_import_widget i }
286
+ end
287
+
288
+ def ruboto_import_widget(class_name, package_name="android.widget")
289
+ view_class = java_import "#{package_name}.#{class_name}"
290
+
291
+ RubotoActivity.class_eval "
292
+ def #{(class_name.to_s.gsub(/([A-Z])/) { '_' + $1.downcase })[1..-1]}(params={})
293
+ force_style = params.delete(:default_style)
294
+ force_parent = params.delete(:parent)
295
+ force_index = params.delete(:parent_index)
296
+ if force_style
297
+ if params.any?
298
+ attributes = android.util.AttributeSet.impl do |method, *args|
299
+ puts 'Not implemented, yet.'
300
+ puts %Q{Unhandled AttributeSet method: \#{method}(\#{args.map{|a| a.inspect}.join(', ')})}
301
+ end
302
+ else
303
+ attributes = nil
304
+ end
305
+ rv = #{class_name}.new(self, attributes, force_style)
306
+ else
307
+ if api_key = params.delete(:apiKey)
308
+ rv = #{class_name}.new(self, api_key)
309
+ else
310
+ rv = #{class_name}.new(self)
311
+ end
312
+ end
313
+
314
+ if force_index
315
+ (force_parent || @view_parent).addView(rv, force_index) if (force_parent || @view_parent)
316
+ else
317
+ (force_parent || @view_parent).addView(rv) if (force_parent || @view_parent)
318
+ end
319
+
320
+ rv.configure self, params
321
+
322
+ if block_given?
323
+ old_view_parent, @view_parent = @view_parent, rv
324
+ yield
325
+ @view_parent = old_view_parent
326
+ end
327
+ rv
328
+ end
329
+ "
330
+
331
+ setup_list_view if class_name == :ListView
332
+ setup_spinner if class_name == :Spinner
333
+ setup_button if class_name == :Button
334
+ setup_image_button if class_name == :ImageButton
335
+ setup_linear_layout if class_name == :LinearLayout
336
+ setup_relative_layout if class_name == :RelativeLayout
337
+ end
338
+
339
+ #############################################################################
340
+ #
341
+ # Extend Common View Classes
342
+ #
343
+
344
+ def setup_view
345
+ java_import "android.view.View"
346
+ java_import "android.view.ViewGroup"
347
+
348
+ View.class_eval do
349
+ @@convert_constants ||= {}
350
+
351
+ def self.add_constant_conversion(from, to)
352
+ @@convert_constants[from] = to
353
+ end
354
+
355
+ def self.convert_constant(from)
356
+ @@convert_constants[from] or from
357
+ end
358
+
359
+ def self.setup_constant_conversion
360
+ (self.constants - self.superclass.constants).each do |i|
361
+ View.add_constant_conversion i.downcase.to_sym, self.const_get(i)
362
+ end
363
+ end
364
+
365
+ def configure(context, params = {})
366
+ if width = params.delete(:width)
367
+ getLayoutParams.width = View.convert_constant(width)
368
+ end
369
+
370
+ if height = params.delete(:height)
371
+ getLayoutParams.height = View.convert_constant(height)
372
+ end
373
+
374
+ if layout = params.delete(:layout)
375
+ lp = getLayoutParams
376
+ layout.each do |k, v|
377
+ values = (v.is_a?(Array) ? v : [v]).map { |i| @@convert_constants[i] or i }
378
+ lp.send("#{k.to_s.gsub(/_([a-z])/) { $1.upcase }}", *values)
379
+ end
380
+ end
381
+
382
+ params.each do |k, v|
383
+ values = (v.is_a?(Array) ? v : [v]).map { |i| @@convert_constants[i] or i }
384
+ self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) { $2.upcase }}", *values)
385
+ end
386
+ end
387
+ end
388
+
389
+ View.add_constant_conversion :wrap_content, ViewGroup::LayoutParams::WRAP_CONTENT
390
+ View.add_constant_conversion :fill_parent, ViewGroup::LayoutParams::FILL_PARENT
391
+ end
392
+
393
+ #############################################################################
394
+ #
395
+ # Special widget setup
396
+ #
397
+
398
+ def setup_linear_layout
399
+ LinearLayout.setup_constant_conversion
400
+ end
401
+
402
+ def setup_relative_layout
403
+ RelativeLayout.setup_constant_conversion
404
+ end
405
+
406
+ def setup_button
407
+ Button.class_eval do
408
+ def configure(context, params = {})
409
+ setOnClickListener(context)
410
+ super(context, params)
411
+ end
412
+ end
413
+
414
+ ruboto_register_handler("org.ruboto.callbacks.RubotoOnClickListener", "click", Button, "setOnClickListener")
415
+ end
416
+
417
+ def setup_image_button
418
+ ImageButton.class_eval do
419
+ def configure(context, params = {})
420
+ setOnClickListener(context)
421
+ super(context, params)
422
+ end
423
+ end
424
+
425
+ ruboto_register_handler("org.ruboto.callbacks.RubotoOnClickListener", "click", ImageButton, "setOnClickListener")
426
+ end
427
+
428
+ def setup_list_view
429
+ ListView.class_eval do
430
+ attr_reader :adapter, :adapter_list
431
+
432
+ def configure(context, params = {})
433
+ if params.has_key? :list
434
+ @adapter_list = Java::java.util.ArrayList.new
435
+ @adapter_list.addAll(params[:list])
436
+ item_layout = params.delete(:item_layout) || R::layout::simple_list_item_1
437
+ @adapter = Java::android.widget.ArrayAdapter.new(context, item_layout, @adapter_list)
438
+ setAdapter @adapter
439
+ params.delete :list
440
+ end
441
+ if params.has_key? :adapter
442
+ @adapter = params[:adapter]
443
+ end
444
+ setOnItemClickListener(context)
445
+ super(context, params)
446
+ end
447
+
448
+ def reload_list(list)
449
+ @adapter_list.clear
450
+ @adapter_list.addAll(list)
451
+ @adapter.notifyDataSetChanged
452
+ invalidate
453
+ end
454
+ end
455
+
456
+ ruboto_register_handler("org.ruboto.callbacks.RubotoOnItemClickListener", "item_click", ListView, "setOnItemClickListener")
457
+ end
458
+
459
+ def setup_spinner
460
+ Spinner.class_eval do
461
+ attr_reader :adapter, :adapter_list
462
+
463
+ def configure(context, params = {})
464
+ if params.has_key? :list
465
+ @adapter_list = Java::java.util.ArrayList.new
466
+ @adapter_list.addAll(params[:list])
467
+ item_layout = params.delete(:item_layout) || R::layout::simple_spinner_item
468
+ @adapter = Java::android.widget.ArrayAdapter.new(context, item_layout, @adapter_list)
469
+ @adapter.setDropDownViewResource(params.delete(:dropdown_layout) || R::layout::simple_spinner_dropdown_item)
470
+ setAdapter @adapter
471
+ params.delete :list
472
+ end
473
+ setOnItemSelectedListener(context)
474
+ super(context, params)
475
+ end
476
+
477
+ def reload_list(list)
478
+ @adapter.clear
479
+ @adapter.addAll(list)
480
+ @adapter.notifyDataSetChanged
481
+ invalidate
482
+ end
483
+ end
484
+
485
+ ruboto_register_handler("org.ruboto.callbacks.RubotoOnItemSelectedListener", "item_selected", Spinner, "setOnItemSelectedListener")
486
+ end
487
+
488
+ #############################################################################
489
+ #
490
+ # Import a class and set it up for handlers
491
+ #
492
+
493
+ def ruboto_import(package_class)
494
+ klass = java_import package_class
495
+ return unless klass
496
+ ruboto_allow_handlers(klass)
497
+ end
498
+
499
+ #############################################################################
500
+ #
501
+ # Allows RubotoActivity to handle callbacks covering Class based handlers
502
+ #
503
+ def ruboto_register_handler(handler_class, unique_name, for_class, method_name)
504
+ klass_name = handler_class[/.+\.([A-Z].+)/, 1]
505
+ klass = ruboto_import handler_class
506
+
507
+ unless RubotoActivity.method_defined? "#{unique_name}_handler"
508
+ RubotoActivity.class_eval "
509
+ def #{unique_name}_handler
510
+ @#{unique_name}_handler ||= #{klass_name}.new
511
+ end
512
+
513
+ def handle_#{unique_name}(&block)
514
+ #{unique_name}_handler.handle_#{unique_name} &block
515
+ self
516
+ end
517
+ "
518
+ end
519
+
520
+ unless for_class.method_defined? "orig_#{method_name}"
521
+ for_class.class_eval "
522
+ alias_method :orig_#{method_name}, :#{method_name}
523
+ def #{method_name}(handler)
524
+ orig_#{method_name}(handler.kind_of?(RubotoActivity) ? handler.#{unique_name}_handler : handler)
525
+ end
526
+ "
527
+ end
528
+ end
529
+
530
+ #############################################################################
531
+ #
532
+ # RubotoPreferenceActivity Preference Generation
533
+ #
534
+
535
+ def ruboto_import_preferences(*preferences)
536
+ preferences.each { |i| ruboto_import_preference i }
537
+ end
538
+
539
+ def ruboto_import_preference(class_name, package_name="android.preference")
540
+ klass = java_import "#{package_name}.#{class_name}"
541
+ return unless klass
542
+
543
+ setup_preferences
544
+
545
+ RubotoPreferenceActivity.class_eval "
546
+ def #{(class_name.to_s.gsub(/([A-Z])/) { '_' + $1.downcase })[1..-1]}(params={})
547
+ rv = #{class_name}.new self
548
+ rv.configure self, params
549
+ @parent.addPreference(rv) if @parent
550
+ if block_given?
551
+ old_parent, @parent = @parent, rv
552
+ yield
553
+ @parent = old_parent
554
+ end
555
+ rv
556
+ end
557
+ "
558
+ end
559
+
560
+ def setup_preferences
561
+ return if @preferences_setup_complete
562
+
563
+ java_import "android.preference.PreferenceScreen"
564
+ java_import "android.preference.Preference"
565
+ java_import "org.ruboto.RubotoPreferenceActivity"
566
+ ruboto_configure_activity(RubotoPreferenceActivity)
567
+
568
+
569
+ RubotoPreferenceActivity.class_eval do
570
+ def preference_screen(params={})
571
+ rv = self.getPreferenceManager.createPreferenceScreen(self)
572
+ rv.configure self, params
573
+ @parent.addPreference(rv) if @parent
574
+ if block_given?
575
+ old_parent, @parent = @parent, rv
576
+ yield
577
+ @parent = old_parent
578
+ end
579
+ rv
580
+ end
581
+
582
+ def setup_preference_screen &block
583
+ @preference_screen_block = block
584
+ end
585
+
586
+ def on_create(bundle)
587
+ @parent = nil
588
+ setPreferenceScreen(instance_eval &@preference_screen_block) if @preference_screen_block
589
+ instance_eval { @finish_create_block.call } if @finish_create_block
590
+ end
591
+ end
592
+
593
+ Preference.class_eval do
594
+ def configure(context, params = {})
595
+ params.each do |k, v|
596
+ if v.is_a?(Array)
597
+ self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) { $2.upcase }}", *v)
598
+ else
599
+ self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) { $2.upcase }}", v)
600
+ end
601
+ end
602
+ end
603
+ end
604
+
605
+ @preferences_setup_complete = true
606
+ end
607
+
608
+ # Setup activity support
609
+ java_import "org.ruboto.RubotoActivity"
610
+ setup_activity
611
+ ruboto_configure_activity(RubotoActivity)
612
+ ruboto_setup(RubotoActivity)
613
+ setup_view
614
+
615
+ # setup service support
616
+ java_import "org.ruboto.RubotoService"
617
+ ruboto_setup(RubotoService)
618
+
619
+ # setup broadcast receiver support
620
+ java_import "org.ruboto.RubotoBroadcastReceiver"
621
+ ruboto_setup(RubotoBroadcastReceiver, false)