ruboto 0.15.0 → 0.16.0

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +4 -1
  3. data/README.md +44 -43
  4. data/RELEASE_CANDICATE_DOC +10 -12
  5. data/RELEASE_DOC +69 -37
  6. data/Rakefile +47 -27
  7. data/assets/rakelib/ruboto.rake +69 -26
  8. data/assets/src/RubotoActivity.java +17 -4
  9. data/assets/src/RubotoService.java +18 -0
  10. data/assets/src/org/ruboto/EntryPointActivity.java +1 -1
  11. data/assets/src/org/ruboto/JRubyAdapter.java +3 -1
  12. data/assets/src/org/ruboto/ScriptLoader.java +27 -4
  13. data/assets/src/ruboto/activity.rb +4 -3
  14. data/assets/src/ruboto/activity/reload.rb +17 -12
  15. data/assets/src/ruboto/widget.rb +18 -18
  16. data/bin/elevate.exe +0 -0
  17. data/bin/elevate_32.exe +0 -0
  18. data/lib/java_class_gen/android_api.xml +1 -1
  19. data/lib/ruboto/commands/base.rb +3 -5
  20. data/lib/ruboto/util/build.rb +1 -1
  21. data/lib/ruboto/util/emulator.rb +31 -5
  22. data/lib/ruboto/util/setup.rb +183 -68
  23. data/lib/ruboto/util/update.rb +35 -42
  24. data/lib/ruboto/util/xml_element.rb +45 -33
  25. data/lib/ruboto/version.rb +1 -1
  26. data/test/activity/call_super_activity.rb +1 -1
  27. data/test/activity/dialog_fragment_activity.rb +37 -0
  28. data/test/activity/dialog_fragment_activity_test.rb +19 -0
  29. data/test/activity/image_button_activity.rb +2 -1
  30. data/test/activity/navigation_activity_test.rb +2 -1
  31. data/test/activity/no_on_create_activity.rb +17 -0
  32. data/test/activity/no_on_create_activity_test.rb +15 -0
  33. data/test/activity/spinner_activity.rb +51 -0
  34. data/test/activity/spinner_activity_test.rb +65 -0
  35. data/test/activity/stack_activity_test.rb +14 -7
  36. data/test/activity/startup_exception_activity.rb +7 -5
  37. data/test/activity/startup_exception_activity_test.rb +2 -2
  38. data/test/app_test_methods.rb +4 -0
  39. data/test/git_based_gem_test.rb +64 -0
  40. data/test/minimal_app_test.rb +12 -13
  41. data/test/rake_test.rb +1 -0
  42. data/test/ruboto_gen_test.rb +21 -15
  43. data/test/ruboto_update_test.rb +23 -6
  44. data/test/sqldroid_test.rb +0 -1
  45. data/test/test_helper.rb +37 -19
  46. metadata +25 -2
@@ -34,7 +34,7 @@ adb_version_str = `adb version`
34
34
  (puts "Unrecognized adb version: #$1"; exit 1) unless adb_version_str =~ /Android Debug Bridge version (\d+\.\d+\.\d+)/
35
35
  (puts "adb version 1.0.31 or later required. Version found: #$1"; exit 1) unless Gem::Version.new($1) >= Gem::Version.new('1.0.31')
36
36
  android_home = ENV['ANDROID_HOME']
37
- android_home = android_home.gsub("\\", "/") unless android_home.nil?
37
+ android_home = android_home.gsub("\\", '/') unless android_home.nil?
38
38
  if android_home.nil?
39
39
  if (adb_path = which('adb'))
40
40
  android_home = File.dirname(File.dirname(adb_path))
@@ -235,27 +235,25 @@ end
235
235
 
236
236
  file RUBOTO_CONFIG_FILE
237
237
 
238
+ task :jruby_adapter => JRUBY_ADAPTER_FILE
238
239
  file JRUBY_ADAPTER_FILE => RUBOTO_CONFIG_FILE do
239
240
  require 'yaml'
240
- if (heap_alloc = YAML.load(File.read(RUBOTO_CONFIG_FILE))['heap_alloc'])
241
- config = <<EOF
242
- // BEGIN Ruboto HeapAlloc
243
- @SuppressWarnings("unused")
244
- byte[] arrayForHeapAllocation = new byte[#{heap_alloc} * 1024 * 1024];
245
- arrayForHeapAllocation = null;
246
- // END Ruboto HeapAlloc
241
+ marker_topic ='Ruboto HeapAlloc'
242
+ begin_marker = "// BEGIN #{marker_topic}"
243
+ end_marker = "// END #{marker_topic}"
244
+ unless (heap_alloc = YAML.load(File.read(RUBOTO_CONFIG_FILE))['heap_alloc'])
245
+ heap_alloc = 13
246
+ comment = '// '
247
+ end
248
+ config = <<EOF
249
+ #{begin_marker}
250
+ #{comment}@SuppressWarnings("unused")
251
+ #{comment}byte[] arrayForHeapAllocation = new byte[#{heap_alloc} * 1024 * 1024];
252
+ #{comment}arrayForHeapAllocation = null;
253
+ #{end_marker}
247
254
  EOF
248
- else
249
- config = <<EOF
250
- // BEGIN Ruboto HeapAlloc
251
- // @SuppressWarnings("unused")
252
- // byte[] arrayForHeapAllocation = new byte[13 * 1024 * 1024];
253
- // arrayForHeapAllocation = null;
254
- // END Ruboto HeapAlloc
255
- EOF
256
- end
257
255
  source = File.read(JRUBY_ADAPTER_FILE)
258
- heap_alloc_pattern = %r{^\s*// BEGIN Ruboto HeapAlloc\n.*^\s*// END Ruboto HeapAlloc\n}m
256
+ heap_alloc_pattern = %r{^\s*#{begin_marker}\n.*^\s*#{end_marker}\n}m
259
257
  File.open(JRUBY_ADAPTER_FILE, 'w') { |f| f << source.sub(heap_alloc_pattern, config) }
260
258
  end
261
259
 
@@ -281,6 +279,9 @@ task :update_scripts => %w(install:quick) do
281
279
  update_scripts
282
280
  end
283
281
 
282
+ desc 'Copy scripts to emulator or device and reload'
283
+ task :boing => %w(update_scripts:reload)
284
+
284
285
  namespace :update_scripts do
285
286
  desc 'Copy scripts to emulator and restart the app'
286
287
  task :restart => APK_DEPENDENCIES - RUBY_SOURCE_FILES do |t|
@@ -299,7 +300,7 @@ namespace :update_scripts do
299
300
  else
300
301
  update_scripts
301
302
  end
302
- start_app # FIXME(uwe): Should trigger reload of updated scripts
303
+ start_app
303
304
  end
304
305
 
305
306
  desc 'Copy scripts to emulator and reload'
@@ -309,7 +310,13 @@ namespace :update_scripts do
309
310
  start_app
310
311
  else
311
312
  scripts = update_scripts
312
- reload_scripts(scripts) if scripts
313
+ if scripts
314
+ if app_running?
315
+ reload_scripts(scripts)
316
+ else
317
+ start_app
318
+ end
319
+ end
313
320
  end
314
321
  end
315
322
  end
@@ -380,6 +387,10 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
380
387
  definition = Bundler.definition
381
388
  definition.validate_ruby!
382
389
  Bundler::Installer.install(Bundler.root, definition)
390
+ unless Dir["#{BUNDLE_PATH}/bundler/gems/"].empty?
391
+ system("mkdir -p '#{BUNDLE_PATH}/gems'")
392
+ system("mv #{BUNDLE_PATH}/bundler/gems/* #{BUNDLE_PATH}/gems/")
393
+ end
383
394
 
384
395
  # Restore RUBY_ENGINE (limit the scope of this hack)
385
396
  old_verbose, $VERBOSE = $VERBOSE, nil
@@ -389,7 +400,7 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
389
400
  $VERBOSE = old_verbose
390
401
  end
391
402
  Gem.platforms = platforms
392
- Gem.paths = gem_paths["GEM_PATH"]
403
+ Gem.paths = gem_paths['GEM_PATH']
393
404
  else
394
405
  # Bundler.settings[:platform] = Gem::Platform::DALVIK
395
406
  sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH} --platform=dalvik#{sdk_level}"
@@ -527,6 +538,35 @@ Java::json.ext.ParserService.new.basicLoad(JRuby.runtime)
527
538
  FileUtils.rm_rf BUNDLE_PATH
528
539
  end
529
540
 
541
+ desc 'Log activity execution, accepts optional logcat filter'
542
+ task :log, [:filter] do |t, args|
543
+ puts '--- clearing logcat'
544
+ `adb logcat -c`
545
+ filter = args[:filter] ? args[:filter] : '' # filter log with filter-specs like TAG:LEVEL TAG:LEVEL ... '*:S'
546
+ logcat_cmd = "adb logcat ActivityManager #{filter}" # we always need ActivityManager logging to catch activity start
547
+ puts "--- starting logcat: #{logcat_cmd}"
548
+ IO.popen logcat_cmd do |logcat|
549
+ puts "--- waiting for activity #{package}/.#{main_activity} ..."
550
+ activity_started = false
551
+ started_regex = Regexp.new "^\\I/ActivityManager.+Start proc #{package} for activity #{package}/\\.#{main_activity}: pid=(?<pid>\\d+)"
552
+ restarted_regex = Regexp.new "^\\I/ActivityManager.+START u0 {cmp=#{package}/org.ruboto.RubotoActivity.+} from pid (?<pid>\\d+)"
553
+ related_regex = Regexp.new "#{package}|#{main_activity}"
554
+ pid_regex = nil
555
+ logcat.each_line do |line|
556
+ if (activity_start_match = started_regex.match(line) || restarted_regex.match(line))
557
+ activity_started = true
558
+ pid = activity_start_match[:pid]
559
+ pid_regex = Regexp.new "\\( *#{pid}\\): "
560
+ puts "--- activity PID=#{pid}"
561
+ end
562
+ if activity_started && (line =~ pid_regex || line =~ related_regex)
563
+ puts "#{Time.now.strftime('%Y%m%d %H%M%S.%6N')} #{line}"
564
+ end
565
+ end
566
+ puts '--- logcat closed'
567
+ end
568
+ end
569
+
530
570
  # Methods
531
571
 
532
572
  def sdk_level
@@ -717,17 +757,20 @@ def update_scripts
717
757
  return nil
718
758
  end
719
759
 
760
+ def app_running?
761
+ `adb shell ps | egrep -e " #{package}\r$"`.size > 0
762
+ end
763
+
720
764
  def start_app
721
765
  `adb shell am start -a android.intent.action.MAIN -n #{package}/.#{main_activity}`
722
766
  end
723
767
 
724
768
  # Triggers reload of updated scripts and restart of the current activity
725
769
  def reload_scripts(scripts)
726
- scripts.each.with_index do |s, i|
727
- cmd = "adb shell am broadcast -a android.intent.action.VIEW -e file #{s} #{'-e restart YES' if i == (scripts.size - 1)}"
728
- puts cmd
729
- system cmd
730
- end
770
+ s = scripts.map{|s| s.gsub(/[&;]/){|m| "&#{m[0]}"}}.join(';')
771
+ cmd = %Q{adb shell am broadcast -a android.intent.action.VIEW -e reload "#{s}"}
772
+ puts cmd
773
+ system cmd
731
774
  end
732
775
 
733
776
  def stop_app
@@ -60,11 +60,24 @@ public class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
60
60
  }
61
61
  }
62
62
 
63
- // FIXME(uwe): What is this for?
64
- public boolean rubotoAttachable() {
65
- return true;
63
+ public void onDestroy() {
64
+ if (ScriptLoader.isCalledFromJRuby()) {
65
+ super.onDestroy();
66
+ return;
67
+ }
68
+ if (!JRubyAdapter.isInitialized()) {
69
+ Log.i("Method called before JRuby runtime was initialized: RubotoActivity#onDestroy");
70
+ super.onDestroy();
71
+ return;
72
+ }
73
+ String rubyClassName = scriptInfo.getRubyClassName();
74
+ if (rubyClassName == null) {
75
+ super.onDestroy();
76
+ return;
77
+ }
78
+ ScriptLoader.callOnDestroy(this);
66
79
  }
67
- // EMXIF
80
+
68
81
 
69
82
  /****************************************************************************************
70
83
  *
@@ -86,6 +86,24 @@ public class THE_RUBOTO_CLASS THE_ACTION THE_ANDROID_CLASS {
86
86
  }
87
87
  }
88
88
 
89
+ public void onDestroy() {
90
+ if (ScriptLoader.isCalledFromJRuby()) {
91
+ super.onDestroy();
92
+ return;
93
+ }
94
+ if (!JRubyAdapter.isInitialized()) {
95
+ Log.i("Method called before JRuby runtime was initialized: RubotoActivity#onDestroy");
96
+ super.onDestroy();
97
+ return;
98
+ }
99
+ String rubyClassName = scriptInfo.getRubyClassName();
100
+ if (rubyClassName == null) {
101
+ super.onDestroy();
102
+ return;
103
+ }
104
+ ScriptLoader.callOnDestroy(this);
105
+ }
106
+
89
107
 
90
108
  /****************************************************************************************
91
109
  *
@@ -35,7 +35,7 @@ public class EntryPointActivity extends org.ruboto.RubotoActivity {
35
35
  // The Intent to to call when done. Defaults to calling this Activity again.
36
36
  // Override to change.
37
37
  protected Intent futureIntent() {
38
- if (getIntent().getAction().equals(Intent.ACTION_MAIN)) {
38
+ if (!getIntent().getAction().equals(Intent.ACTION_VIEW)) {
39
39
  return new Intent(getIntent()).setAction(Intent.ACTION_VIEW);
40
40
  } else {
41
41
  return getIntent();
@@ -272,6 +272,8 @@ public class JRubyAdapter {
272
272
  addLoadPath(scriptsDirName(appContext));
273
273
  put("$package_name", appContext.getPackageName());
274
274
 
275
+ runScriptlet("::RUBOTO_JAVA_PROXIES = {}");
276
+
275
277
  initialized = true;
276
278
  } catch (ClassNotFoundException e) {
277
279
  handleInitException(e);
@@ -353,7 +355,7 @@ public class JRubyAdapter {
353
355
  // FIXME(uwe): Remove when we stop supporting Ruby 1.8
354
356
  @Deprecated public static boolean isRubyOneNine() {
355
357
  String rv = ((String)get("RUBY_VERSION"));
356
- return rv.startsWith("2.0.") || rv.startsWith("1.9.");
358
+ return rv.startsWith("2.1.") || rv.startsWith("2.0.") || rv.startsWith("1.9.");
357
359
  }
358
360
 
359
361
  static void printStackTrace(Throwable t) {
@@ -1,6 +1,7 @@
1
1
  package org.ruboto;
2
2
 
3
3
  import java.io.IOException;
4
+ import java.util.Map;
4
5
 
5
6
  import android.app.ProgressDialog;
6
7
  import android.content.Context;
@@ -12,7 +13,7 @@ public class ScriptLoader {
12
13
  */
13
14
  public static boolean isCalledFromJRuby() {
14
15
  StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
15
- int maxLookBack = Math.min(9, stackTraceElements.length);
16
+ int maxLookBack = Math.min(8, stackTraceElements.length);
16
17
  for(int i = 0; i < maxLookBack ; i++){
17
18
  if (stackTraceElements[i].getClassName().startsWith("org.jruby.javasupport.JavaMethod")) {
18
19
  return true;
@@ -52,7 +53,6 @@ public class ScriptLoader {
52
53
  JRubyAdapter.put("$java_instance", component);
53
54
  rubyClass = JRubyAdapter.runScriptlet("class << $java_instance; self; end");
54
55
  } else if (JRubyAdapter.isRubyOneNine()) {
55
- JRubyAdapter.runScriptlet("Java::" + component.getClass().getName() + ".__persistent__ = true");
56
56
  rubyClass = JRubyAdapter.runRubyMethod(component, "singleton_class");
57
57
  } else {
58
58
  throw new RuntimeException("Unknown Ruby version: " + JRubyAdapter.get("RUBY_VERSION"));
@@ -67,7 +67,6 @@ public class ScriptLoader {
67
67
  Log.d("Script contains class definition");
68
68
  if (rubyClass == null && hasBackingJavaClass) {
69
69
  Log.d("Script has separate Java class");
70
- JRubyAdapter.runScriptlet("Java::" + component.getClass().getName() + ".__persistent__ = true");
71
70
  rubyClass = JRubyAdapter.runScriptlet("Java::" + component.getClass().getName());
72
71
  }
73
72
  Log.d("Set class: " + rubyClass);
@@ -116,16 +115,40 @@ public class ScriptLoader {
116
115
  }
117
116
 
118
117
  public static final void callOnCreate(final RubotoComponent component, Object... args) {
118
+ persistObjectProxy(component);
119
119
  if (component instanceof android.content.Context) {
120
120
  Log.d("Call onCreate on: " + component.getScriptInfo().getRubyInstance());
121
121
  // FIXME(uwe): Simplify when we stop support for snake case aliasing interface callback methods.
122
122
  if ((Boolean)JRubyAdapter.runScriptlet(component.getScriptInfo().getRubyClassName() + ".instance_methods(false).any?{|m| m.to_sym == :onCreate}")) {
123
123
  JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onCreate", args);
124
- } else if ((Boolean)JRubyAdapter.runScriptlet(component.getScriptInfo().getRubyClassName() + ".instance_methods(false).any?{|m| m.to_sym == :on_create}")) {
124
+ } else if ((Boolean)JRubyAdapter.runScriptlet(component.getScriptInfo().getRubyClassName() + ".instance_methods(true).any?{|m| m.to_sym == :on_create}")) {
125
125
  JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "on_create", args);
126
+ } else {
127
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onCreate", args);
126
128
  }
127
129
  // EMXIF
128
130
  }
129
131
  }
130
132
 
133
+ public static final void callOnDestroy(final RubotoComponent component) {
134
+ String rubyClassName = component.getScriptInfo().getRubyClassName();
135
+ if ((Boolean)JRubyAdapter.runScriptlet(rubyClassName + ".instance_methods(false).any?{|m| m.to_sym == :onDestroy}")) {
136
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onDestroy");
137
+ } else if ((Boolean)JRubyAdapter.runScriptlet(rubyClassName + ".instance_methods(true).any?{|m| m.to_sym == :on_destroy}")) {
138
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "on_destroy");
139
+ } else {
140
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onDestroy");
141
+ }
142
+ releaseObjectProxy(component);
143
+ }
144
+
145
+ private static void persistObjectProxy(RubotoComponent component) {
146
+ JRubyAdapter.runScriptlet("Java::" + component.getClass().getName() + ".__persistent__ = true");
147
+ ((Map)JRubyAdapter.get("RUBOTO_JAVA_PROXIES")).put(component.getScriptInfo().getRubyInstance(), component.getScriptInfo().getRubyInstance());
148
+ }
149
+
150
+ private static void releaseObjectProxy(RubotoComponent component) {
151
+ ((Map)JRubyAdapter.get("RUBOTO_JAVA_PROXIES")).remove(component.getScriptInfo().getRubyInstance());
152
+ }
153
+
131
154
  }
@@ -62,8 +62,9 @@ module Ruboto
62
62
  raise "Unknown options: #{options}" unless options.empty?
63
63
 
64
64
  if class_name.nil? && block_given?
65
+ src_desc = source_descriptor(block)
65
66
  class_name =
66
- "#{java_class.name.split('::').last}_#{source_descriptor(block)[0].split('/').last.gsub(/[.-]+/, '_')}_#{source_descriptor(block)[1]}"
67
+ "#{java_class.name.split('::').last}_#{src_desc[0].split('/').last.gsub(/[.-]+/, '_')}_#{src_desc[1]}"
67
68
  end
68
69
 
69
70
  class_name = class_name.to_s
@@ -85,8 +86,8 @@ module Ruboto
85
86
 
86
87
  private
87
88
 
88
- def source_descriptor(proc)
89
- if md = /^#<Proc:0x[0-9A-Fa-f]+@(.+):(\d+)(?: \(lambda\))?>$/.match(proc.inspect)
89
+ def source_descriptor(src_proc)
90
+ if (md = /^#<Proc:0x[0-9A-Fa-f-]+@(.+):(\d+)(?: \(lambda\))?>$/.match(src_proc.inspect))
90
91
  filename, line = md.captures
91
92
  return filename, line.to_i
92
93
  end
@@ -1,14 +1,16 @@
1
+ require 'ruboto/activity'
2
+
1
3
  module Ruboto::Activity::Reload
2
4
  import org.ruboto.Log
3
5
 
4
6
  def onResume
5
- Log.d "Ruboto::Activity::Reload onResume"
7
+ Log.d 'Ruboto::Activity::Reload onResume'
6
8
  super
7
9
 
8
10
  @ruboto_activity_reload_receiver = ReloadReceiver.new(self)
9
11
  filter = android.content.IntentFilter.new(android.content.Intent::ACTION_VIEW)
10
12
  registerReceiver(@ruboto_activity_reload_receiver, filter)
11
- Log.d "Ruboto::Activity::Reload registered reload receiver"
13
+ Log.d 'Ruboto::Activity::Reload registered reload receiver'
12
14
  rescue Exception
13
15
  Log.e "Exception registering reload listener: #{$!.message}"
14
16
  Log.e $!.backtrace.join("\n")
@@ -18,7 +20,7 @@ module Ruboto::Activity::Reload
18
20
  super
19
21
  unregisterReceiver(@ruboto_activity_reload_receiver)
20
22
  @ruboto_activity_reload_receiver = nil
21
- Log.d "Ruboto::Activity::Reload unregistered reload receiver"
23
+ Log.d 'Ruboto::Activity::Reload unregistered reload receiver'
22
24
  rescue Exception
23
25
  Log.e "Exception unregistering reload listener: #{$!.message}"
24
26
  Log.e $!.backtrace.join("\n")
@@ -38,17 +40,20 @@ module Ruboto::Activity::Reload
38
40
  # but have not found a way to do that.
39
41
  def onReceive(context, reload_intent)
40
42
  Log.d "Got reload intent: #{reload_intent.inspect}"
41
- file = reload_intent.get_string_extra('file')
42
- if file
43
- Log.d "load file: #{file.inspect}"
44
- load file
45
- end
46
- if (reload_intent.get_string_extra('restart'))
43
+ file_string = reload_intent.get_string_extra('reload')
44
+ if file_string
45
+ files = file_string.split(/(?<!&);/).map { |f| f.gsub(/&(.)/) { |m| m[1] } }
46
+ files.each do |file|
47
+ Log.d "load file: #{file.inspect}"
48
+ load file
49
+ end
47
50
  Log.d 'restart activity'
48
- if @activity.intent.action == android.content.Intent::ACTION_MAIN
49
- restart_intent = android.content.Intent.new(@activity.intent).setAction(android.content.Intent::ACTION_VIEW)
51
+ if @activity.intent.action == android.content.Intent::ACTION_MAIN ||
52
+ @activity.intent.action == android.hardware.usb.UsbManager::ACTION_USB_DEVICE_ATTACHED
53
+ restart_intent = android.content.Intent.new(@activity.intent).
54
+ setAction(android.content.Intent::ACTION_VIEW)
50
55
  else
51
- restart_intent = @activity.intent
56
+ restart_intent = @activity.intent
52
57
  end
53
58
  @activity.startActivity(restart_intent)
54
59
  @activity.finish
@@ -109,7 +109,7 @@ def ruboto_import_widget(class_name, package_name='android.widget')
109
109
 
110
110
  return unless klass
111
111
 
112
- RubotoActivity.class_eval "
112
+ method_str = "
113
113
  def #{(class_name.to_s.gsub(/([A-Z])/) { '_' + $1.downcase })[1..-1]}(params={})
114
114
  if force_style = params.delete(:default_style)
115
115
  rv = #{class_name}.new(self, nil, force_style)
@@ -134,6 +134,13 @@ def ruboto_import_widget(class_name, package_name='android.widget')
134
134
  rv
135
135
  end
136
136
  "
137
+ RubotoActivity.class_eval method_str
138
+
139
+ # FIXME(uwe): Remove condition when we stop support for api level < 11
140
+ if android.os.Build::VERSION::SDK_INT >= 11
141
+ android.app.Fragment.class_eval method_str.gsub('self', 'activity')
142
+ end
143
+ # EMXIF
137
144
 
138
145
  setup_list_view if class_name == :ListView
139
146
  setup_spinner if class_name == :Spinner
@@ -166,14 +173,12 @@ def setup_image_button
166
173
  end
167
174
 
168
175
  def setup_list_view
169
- Java::android.widget.ListView.__persistent__ = true
170
- Java::android.widget.ListView.class_eval do
176
+ android.widget.ListView.__persistent__ = true
177
+ android.widget.ListView.class_eval do
171
178
  def configure(context, params = {})
172
179
  if (list = params.delete(:list))
173
- @adapter_list = Java::java.util.ArrayList.new
174
- @adapter_list.addAll(list)
175
180
  item_layout = params.delete(:item_layout) || R::layout::simple_list_item_1
176
- params[:adapter] = Java::android.widget.ArrayAdapter.new(context, item_layout, @adapter_list)
181
+ params[:adapter] = android.widget.ArrayAdapter.new(context, item_layout, list)
177
182
  end
178
183
  super(context, params)
179
184
  end
@@ -188,19 +193,14 @@ def setup_list_view
188
193
  end
189
194
 
190
195
  def setup_spinner
191
- Java::android.widget.Spinner.__persistent__ = true
192
- Java::android.widget.Spinner.class_eval do
193
- attr_reader :adapter, :adapter_list
194
-
196
+ android.widget.Spinner.__persistent__ = true
197
+ android.widget.Spinner.class_eval do
195
198
  def configure(context, params = {})
196
- if params.has_key? :list
197
- @adapter_list = Java::java.util.ArrayList.new
198
- @adapter_list.addAll(params[:list])
199
- item_layout = params.delete(:item_layout) || R::layout::simple_spinner_item
200
- @adapter = Java::android.widget.ArrayAdapter.new(context, item_layout, @adapter_list)
201
- @adapter.setDropDownViewResource(params.delete(:dropdown_layout) || R::layout::simple_spinner_dropdown_item)
202
- setAdapter @adapter
203
- params.delete :list
199
+ if (list = params.delete(:list))
200
+ item_layout = params.delete(:item_layout)
201
+ params[:adapter] = android.widget.ArrayAdapter.new(context, item_layout || R::layout::simple_spinner_item, list)
202
+ dropdown_layout = params.delete(:dropdown_layout)
203
+ params[:adapter].setDropDownViewResource(dropdown_layout) if dropdown_layout
204
204
  end
205
205
  super(context, params)
206
206
  end