ruboto 0.5.2

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