ruboto-core 0.1.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +2 -1
- data/README.md +1 -1
- data/Rakefile +2 -2
- data/assets/Rakefile +181 -60
- data/assets/assets/scripts/ruboto.rb +249 -133
- data/assets/samples/sample_activity.rb +4 -4
- data/assets/src/InheritingActivity.java +8 -6
- data/assets/src/InheritingBroadcastReceiver.java +5 -5
- data/assets/src/InheritingClass.java +3 -3
- data/assets/src/InheritingService.java +3 -4
- data/assets/src/RubotoActivity.java +30 -15
- data/assets/src/RubotoBroadcastReceiver.java +6 -13
- data/assets/src/RubotoService.java +4 -3
- data/assets/src/org/ruboto/Script.java +117 -58
- data/assets/src/org/ruboto/test/ActivityTest.java +23 -17
- data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +10 -6
- data/lib/java_class_gen/InheritingClass.java.erb +0 -1
- data/lib/java_class_gen/android_api.xml +1 -1
- data/lib/ruboto/commands/base.rb +227 -255
- data/lib/ruboto/util/build.rb +33 -22
- data/lib/ruboto/util/update.rb +210 -40
- data/lib/ruboto/util/verify.rb +4 -0
- data/lib/ruboto/util/xml_element.rb +28 -18
- data/test/activity/image_button.rb +21 -0
- data/test/activity/image_button_and_button.rb +31 -0
- data/test/activity/image_button_and_button_test.rb +27 -0
- data/test/activity/image_button_test.rb +21 -0
- data/test/app_test_methods.rb +54 -0
- data/test/rake_test.rb +53 -0
- data/test/ruboto_gen_test.rb +36 -0
- data/test/ruboto_update_test.rb +61 -0
- data/test/service_test.rb +49 -0
- data/test/test_helper.rb +113 -3
- metadata +44 -46
- data/test/app_test.rb +0 -44
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -163,7 +163,7 @@ You can update various portions of your generated Ruboto app through the ruboto
|
|
163
163
|
|
164
164
|
$ ruboto gen core Activity --method_base all-on-or-none --method_include specific-methods-to-include --method_include specific-methods-to-exclude
|
165
165
|
|
166
|
-
4) The generator will load up the SDK information and find the specified methods. The generator will abort around methods that were added or deprecated based on the SDK levels. You can either
|
166
|
+
4) The generator will load up the SDK information and find the specified methods. The generator will abort around methods that were added or deprecated based on the SDK levels. You can either use method_exclude to remove methods individually or add '--force exclude' to remove the all. You can also us '--force include' to create them anyway (added methods are created without calling super to avoid crashin on legacy hardware).
|
167
167
|
|
168
168
|
Scripts
|
169
169
|
-------
|
data/Rakefile
CHANGED
data/assets/Rakefile
CHANGED
@@ -1,59 +1,35 @@
|
|
1
|
-
|
2
|
-
# and inspect on the hash) on a device. Bring it off the device and put it in the callback_gen dir.
|
3
|
-
#
|
4
|
-
# Move this into a rake task later.
|
5
|
-
#
|
1
|
+
require 'time'
|
6
2
|
|
3
|
+
def manifest() @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
|
4
|
+
def package() manifest.root.attribute('package') end
|
5
|
+
def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
ant_loaded = true
|
12
|
-
end
|
7
|
+
UPDATE_MARKER_FILE = File.expand_path(File.join('tmp', 'LAST_UPDATE'), File.dirname(__FILE__))
|
8
|
+
BUNDLE_JAR = 'libs/bundle.jar'
|
9
|
+
BUNDLE_PATH = 'tmp/bundle'
|
13
10
|
|
14
11
|
require 'rake/clean'
|
15
12
|
require 'rexml/document'
|
16
13
|
|
17
|
-
generated_libs = 'generated_libs'
|
18
14
|
jars = Dir['libs/*.jar']
|
19
15
|
stdlib = jars.grep(/stdlib/).first #libs/jruby-stdlib-VERSION.jar
|
20
16
|
jruby_jar = jars.grep(/core/).first #libs/jruby-core-VERSION.jar
|
21
|
-
|
22
|
-
|
23
|
-
ant.property :name=>'external.libs.dir', :value => generated_libs if ant_loaded
|
24
|
-
dirs = ['tmp/ruby', 'tmp/precompiled', generated_libs]
|
25
|
-
dirs.each { |d| directory d }
|
26
|
-
|
27
|
-
CLEAN.include('tmp', 'bin', generated_libs)
|
28
|
-
|
29
|
-
ant_import if ant_loaded
|
30
|
-
|
31
|
-
file stdlib_precompiled => :compile_stdlib
|
32
|
-
file jruby_ruboto_jar => generated_libs do
|
33
|
-
ant.zip(:destfile=>jruby_ruboto_jar) do
|
34
|
-
zipfileset(:src=>jruby_jar) do
|
35
|
-
exclude(:name=>'jni/**')
|
36
|
-
# dx chokes on some of the netdb classes, for some reason
|
37
|
-
exclude(:name=>'jnr/netdb/**')
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
17
|
+
MANIFEST_FILE = 'AndroidManifest.xml'
|
18
|
+
APK_FILE = "bin/#{build_project_name}-debug.apk"
|
41
19
|
|
42
|
-
|
43
|
-
task :compile_stdlib => [:clean, *dirs] do
|
44
|
-
ant.unzip(:src=>stdlib, :dest=>'tmp/ruby')
|
45
|
-
Dir.chdir('tmp/ruby') { sh "jrubyc . -t ../precompiled" }
|
46
|
-
ant.zip(:destfile=>stdlib_precompiled, :basedir=>'tmp/precompiled')
|
47
|
-
end
|
20
|
+
CLEAN.include('tmp', 'bin')
|
48
21
|
|
49
|
-
task :
|
50
|
-
cp stdlib, generated_libs
|
51
|
-
end
|
22
|
+
task :default => :debug
|
52
23
|
|
53
|
-
|
54
|
-
task :
|
24
|
+
desc 'build debug package'
|
25
|
+
task :debug => [BUNDLE_JAR, :mark_update] do
|
26
|
+
sh 'ant debug'
|
27
|
+
end
|
55
28
|
|
56
|
-
|
29
|
+
desc "build package and install it on the emulator or device"
|
30
|
+
task :install => [BUNDLE_JAR, :mark_update] do
|
31
|
+
sh 'ant install'
|
32
|
+
end
|
57
33
|
|
58
34
|
task :tag => :release do
|
59
35
|
unless `git branch` =~ /^\* master$/
|
@@ -78,6 +54,11 @@ task :publish => :align do
|
|
78
54
|
puts "#{build_project_name}.apk is ready for the market!"
|
79
55
|
end
|
80
56
|
|
57
|
+
desc 'Start the emulator with larger disk'
|
58
|
+
task :emulator do
|
59
|
+
system 'emulator -partition-size 1024 -avd Android_3.0'
|
60
|
+
end
|
61
|
+
|
81
62
|
task :start_app do
|
82
63
|
`adb shell am start -a android.intent.action.MAIN -n #{package}/.#{main_activity}`
|
83
64
|
end
|
@@ -86,33 +67,65 @@ task :stop_app do
|
|
86
67
|
`adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
|
87
68
|
end
|
88
69
|
|
70
|
+
desc 'Restart the application'
|
89
71
|
task :restart => [:stop_app, :start_app]
|
90
72
|
|
91
73
|
task :uninstall do
|
74
|
+
puts "Uninstalling package #{package}"
|
92
75
|
system "adb uninstall #{package}"
|
93
76
|
end
|
94
77
|
|
95
78
|
namespace :install do
|
79
|
+
desc 'Uninstall, build, and install the application'
|
80
|
+
task :clean => [:uninstall, :install]
|
81
|
+
|
96
82
|
desc 'Build, install, and restart the application'
|
97
83
|
task :restart => [:install, :start_app]
|
84
|
+
|
98
85
|
namespace :restart do
|
99
86
|
desc 'Uninstall, build, install, and restart the application'
|
100
87
|
task :clean => [:uninstall, :install, :start_app]
|
101
88
|
end
|
102
89
|
end
|
103
90
|
|
104
|
-
|
105
|
-
|
106
|
-
|
91
|
+
file MANIFEST_FILE
|
92
|
+
|
93
|
+
file APK_FILE => MANIFEST_FILE do
|
94
|
+
puts "#{MANIFEST_FILE} changed. Forcing rebuild of #{APK_FILE}."
|
95
|
+
Rake::Task['install:clean'].invoke
|
96
|
+
end
|
97
|
+
|
98
|
+
desc 'Copy scripts to emulator or device'
|
99
|
+
task :update_scripts => [BUNDLE_JAR, APK_FILE] do
|
100
|
+
sdcard_path = "/mnt/sdcard/Android/data/#{package}/files"
|
101
|
+
app_files_path = "/data/data/#{package}/files"
|
102
|
+
if package_installed? && device_path_exists?(sdcard_path)
|
103
|
+
puts 'Pushing files to apk public file area.'
|
104
|
+
data_dir = sdcard_path
|
105
|
+
elsif package_installed? && device_path_exists?(app_files_path)
|
106
|
+
puts 'Pushing files to apk private file area.'
|
107
|
+
data_dir = app_files_path
|
108
|
+
else
|
109
|
+
puts 'Cannot find the scripts directory on the device.'
|
110
|
+
puts 'If you have a non-rooted device, you need to add'
|
111
|
+
puts %q{ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />}
|
112
|
+
puts 'to the AndroidManifest.xml file to enable the update_scripts rake task.'
|
113
|
+
puts "Reverting to uninstalling and re-installing the apk."
|
114
|
+
Rake::Task['install:clean'].invoke
|
115
|
+
next
|
116
|
+
end
|
117
|
+
last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
|
107
118
|
Dir.chdir('assets') do
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
next if File.
|
112
|
-
|
119
|
+
['scripts'].each do |asset_dir|
|
120
|
+
Dir["#{asset_dir}/*"].each do |asset_file|
|
121
|
+
next if File.directory? asset_file
|
122
|
+
next if File.ctime(asset_file) < last_update
|
123
|
+
print "#{asset_file}: " ; $stdout.flush
|
124
|
+
`adb push #{asset_file} #{data_dir}/#{asset_file}`
|
113
125
|
end
|
114
126
|
end
|
115
127
|
end
|
128
|
+
mark_update
|
116
129
|
end
|
117
130
|
|
118
131
|
namespace :update_scripts do
|
@@ -121,10 +134,19 @@ namespace :update_scripts do
|
|
121
134
|
end
|
122
135
|
|
123
136
|
task :update_test_scripts do
|
124
|
-
|
125
|
-
|
137
|
+
test_scripts_path = "/data/data/#{package}.tests/files/scripts"
|
138
|
+
# TODO(uwe): Investigate if we can just push the scripts instead of building and installing the instrumentation APK
|
139
|
+
if false && package_installed?(true) && device_path_exists?(test_scripts_path)
|
140
|
+
Dir['test/assets/scripts/*.rb'].each do |script|
|
141
|
+
print "#{script}: " ; $stdout.flush
|
142
|
+
`adb push #{script} #{test_scripts_path}`
|
143
|
+
end
|
144
|
+
`adb shell ps | grep #{package}.tests | awk '{print $2}' | xargs adb shell kill`
|
145
|
+
else
|
146
|
+
Dir.chdir 'test' do
|
147
|
+
sh 'ant install'
|
148
|
+
end
|
126
149
|
end
|
127
|
-
`adb shell ps | grep #{package}.tests | awk '{print $2}' | xargs adb shell kill`
|
128
150
|
end
|
129
151
|
|
130
152
|
task :test => :uninstall do
|
@@ -139,13 +161,74 @@ namespace :test do
|
|
139
161
|
task :quick => [:update_scripts, :update_test_scripts] do
|
140
162
|
Dir.chdir('test') do
|
141
163
|
puts 'Running quick tests'
|
142
|
-
|
164
|
+
sh "ant run-tests-quick"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
file 'Gemfile'
|
170
|
+
|
171
|
+
desc 'Generate bundle jar from Gemfile'
|
172
|
+
file BUNDLE_JAR => 'Gemfile' do
|
173
|
+
next unless File.exists? 'Gemfile'
|
174
|
+
puts "Generating #{BUNDLE_JAR}"
|
175
|
+
|
176
|
+
FileUtils.mkdir_p BUNDLE_PATH
|
177
|
+
sh "bundle install --path=#{BUNDLE_PATH}"
|
178
|
+
|
179
|
+
# FIXME(uwe): Should not be necessary. ARJDBC should not offer the same files as AR.
|
180
|
+
|
181
|
+
Dir.chdir "#{BUNDLE_PATH}/ruby/1.8/gems" do
|
182
|
+
scanned_files = []
|
183
|
+
Dir["*/lib/**/*"].each do |f|
|
184
|
+
raise "Malformed file name" unless f =~ %r{^(.*?)/lib/(.*)$}
|
185
|
+
gem_name, lib_file = $1, $2
|
186
|
+
if existing_file = scanned_files.find{|sf| sf =~ %r{(.*?)/lib/#{lib_file}}}
|
187
|
+
puts "Removing duplicate of file #{lib_file} in gem #{gem_name}"
|
188
|
+
puts "Already present in gem #{$1}"
|
189
|
+
end
|
143
190
|
end
|
144
191
|
end
|
192
|
+
|
193
|
+
# FIXME(uwe): Remove when directory listing in apk subdirectories work.
|
194
|
+
# FIXME(uwe): http://jira.codehaus.org/browse/JRUBY-5775
|
195
|
+
Dir["#{BUNDLE_PATH}/ruby/1.8/gems/activesupport-*/lib/active_support/core_ext.rb"].each do |faulty_file|
|
196
|
+
faulty_code = <<-'EOF'
|
197
|
+
Dir["#{File.dirname(__FILE__)}/core_ext/*.rb"].sort.each do |path|
|
198
|
+
require "active_support/core_ext/#{File.basename(path, '.rb')}"
|
145
199
|
end
|
200
|
+
EOF
|
201
|
+
replace_faulty_code(faulty_file, faulty_code)
|
202
|
+
end
|
146
203
|
|
147
|
-
|
148
|
-
|
204
|
+
Dir["#{BUNDLE_PATH}/ruby/1.8/gems/activemodel-*/lib/active_model/validations.rb"].each do |faulty_file|
|
205
|
+
faulty_code = <<-EOF
|
206
|
+
Dir[File.dirname(__FILE__) + "/validations/*.rb"].sort.each do |path|
|
207
|
+
filename = File.basename(path)
|
208
|
+
require "active_model/validations/\#{filename}"
|
209
|
+
end
|
210
|
+
EOF
|
211
|
+
replace_faulty_code(faulty_file, faulty_code)
|
212
|
+
end
|
213
|
+
|
214
|
+
FileUtils.rm_f BUNDLE_JAR
|
215
|
+
Dir["#{BUNDLE_PATH}/ruby/1.8/gems/*"].each_with_index do |gem_dir, i|
|
216
|
+
`jar #{i == 0 ? 'c' : 'u'}f #{BUNDLE_JAR} -C #{gem_dir}/lib .`
|
217
|
+
end
|
218
|
+
FileUtils.rm_rf BUNDLE_PATH
|
219
|
+
|
220
|
+
Rake::Task['install'].invoke
|
221
|
+
end
|
222
|
+
|
223
|
+
task :mark_update do
|
224
|
+
mark_update
|
225
|
+
end
|
226
|
+
|
227
|
+
# Methods
|
228
|
+
|
229
|
+
def mark_update
|
230
|
+
FileUtils.mkdir_p File.dirname(UPDATE_MARKER_FILE)
|
231
|
+
File.open(UPDATE_MARKER_FILE, 'w'){|f| f << Time.now.iso8601}
|
149
232
|
end
|
150
233
|
|
151
234
|
def strings(name)
|
@@ -154,8 +237,46 @@ def strings(name)
|
|
154
237
|
value.text
|
155
238
|
end
|
156
239
|
|
157
|
-
def package() manifest.root.attribute('package') end
|
158
240
|
def version() strings :version_name end
|
241
|
+
|
159
242
|
def app_name() strings :app_name end
|
160
|
-
|
161
|
-
def
|
243
|
+
|
244
|
+
def main_activity() manifest.root.elements['application'].elements["activity[@android:label='@string/app_name']"].attribute('android:name') end
|
245
|
+
|
246
|
+
def device_path_exists?(path)
|
247
|
+
path_output =`adb shell ls #{path}`
|
248
|
+
result = path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
|
249
|
+
puts "Checking path on device: #{path}: #{result || path_output}"
|
250
|
+
result
|
251
|
+
end
|
252
|
+
|
253
|
+
def package_installed? test = false
|
254
|
+
package_name = "#{package}#{'.tests' if test}"
|
255
|
+
app_paths = ['', '-0', '-1', '-2'].map{|i| "/data/app/#{package_name}#{i}.apk"}
|
256
|
+
path_outputs = app_paths.map{|p| `adb shell ls #{p}`.chomp}
|
257
|
+
path_outputs.each_with_index do |o, i|
|
258
|
+
if o == app_paths[i]
|
259
|
+
puts "Found package #{app_paths[i]}"
|
260
|
+
return true
|
261
|
+
end
|
262
|
+
end
|
263
|
+
puts "Package not found: #{package_name}"
|
264
|
+
return false
|
265
|
+
end
|
266
|
+
|
267
|
+
private
|
268
|
+
|
269
|
+
def replace_faulty_code(faulty_file, faulty_code)
|
270
|
+
explicit_requires = Dir["#{faulty_file.chomp('.rb')}/*.rb"].sort.map{|f| File.basename(f)}.map do |filename|
|
271
|
+
"require 'active_model/validations/#{filename}'"
|
272
|
+
end.join("\n")
|
273
|
+
|
274
|
+
old_code = File.read(faulty_file)
|
275
|
+
new_code = old_code.gsub faulty_code, explicit_requires
|
276
|
+
if new_code != old_code
|
277
|
+
puts "Replaced directory listing code in file #{faulty_file} with explicit requires."
|
278
|
+
File.open(faulty_file, 'w'){|f| f << new_code}
|
279
|
+
else
|
280
|
+
puts "Could not find expected faulty code\n\n#{faulty_code}\n\nin file #{faulty_file}\n\n#{old_code}\n\n"
|
281
|
+
end
|
282
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#######################################################
|
2
2
|
#
|
3
|
-
# ruboto.rb
|
3
|
+
# ruboto.rb
|
4
4
|
#
|
5
5
|
# - Wrapper for using RubotoActivity, RubotoService, and
|
6
6
|
# RubotoBroadcastReceiver.
|
@@ -9,7 +9,7 @@
|
|
9
9
|
#
|
10
10
|
#######################################################
|
11
11
|
|
12
|
-
$RUBOTO_VERSION =
|
12
|
+
$RUBOTO_VERSION = 8
|
13
13
|
|
14
14
|
def confirm_ruboto_version(required_version, exact=true)
|
15
15
|
raise "requires $RUBOTO_VERSION=#{required_version} or greater, current version #{$RUBOTO_VERSION}" if $RUBOTO_VERSION < required_version and not exact
|
@@ -18,7 +18,15 @@ end
|
|
18
18
|
|
19
19
|
require 'java'
|
20
20
|
|
21
|
-
$package_name =
|
21
|
+
$package_name = ($activity || $service || $broadcast_receiver).package_name
|
22
|
+
$package = eval("Java::#{$package_name}")
|
23
|
+
|
24
|
+
# Create convenience method for top-level android package so we do not need to prefix with 'Java::'.
|
25
|
+
module Kernel
|
26
|
+
def android
|
27
|
+
JavaUtilities.get_package_module_dot_format('android')
|
28
|
+
end
|
29
|
+
end
|
22
30
|
|
23
31
|
java_import "android.R"
|
24
32
|
|
@@ -32,53 +40,77 @@ module Ruboto
|
|
32
40
|
end
|
33
41
|
AndroidIds = JavaUtilities.get_proxy_class("android.R$id")
|
34
42
|
|
43
|
+
class Object
|
44
|
+
def with_large_stack(opts = {}, &block)
|
45
|
+
opts = {:size => opts} if opts.is_a? Integer
|
46
|
+
opts = {:name => 'Block with large stack'}.update(opts)
|
47
|
+
result = nil
|
48
|
+
t = Thread.with_large_stack(opts, &proc{result = block.call})
|
49
|
+
t.join
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Thread
|
55
|
+
def self.with_large_stack(opts = {}, &block)
|
56
|
+
opts = {:size => opts} if opts.is_a? Integer
|
57
|
+
stack_size_kb = opts.delete(:size) || 64
|
58
|
+
name = opts.delete(:name) || "Thread with large stack"
|
59
|
+
raise "Unknown option(s): #{opts.inspect}" unless opts.empty?
|
60
|
+
t = java.lang.Thread.new(nil, block, name, stack_size_kb * 1024)
|
61
|
+
t.start
|
62
|
+
t
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
35
66
|
#############################################################################
|
36
67
|
#
|
37
68
|
# Activity
|
38
69
|
#
|
39
70
|
|
40
71
|
def setup_activity
|
41
|
-
|
42
|
-
|
43
|
-
Activity.class_eval do
|
44
|
-
def start_ruboto_dialog(remote_variable, &block)
|
45
|
-
start_ruboto_activity(remote_variable, RubotoDialog, &block)
|
46
|
-
end
|
72
|
+
java_import "android.app.Activity"
|
47
73
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
if @initialized or self == $activity
|
52
|
-
b = Java::android.os.Bundle.new
|
53
|
-
b.putString("Remote Variable", remote_variable)
|
54
|
-
b.putBoolean("Define Remote Variable", true)
|
55
|
-
b.putString("Initialize Script", "#{remote_variable}.initialize_activity")
|
56
|
-
|
57
|
-
i = Java::android.content.Intent.new
|
58
|
-
i.setClass self, klass.java_class
|
59
|
-
i.putExtra("RubotoActivity Config", b)
|
60
|
-
|
61
|
-
self.startActivity i
|
62
|
-
else
|
63
|
-
instance_eval "#{remote_variable}=self"
|
64
|
-
setRemoteVariable remote_variable
|
65
|
-
initialize_activity
|
66
|
-
on_create nil
|
74
|
+
Activity.class_eval do
|
75
|
+
def start_ruboto_dialog(remote_variable, theme=R.style::Theme_Dialog, &block)
|
76
|
+
start_ruboto_activity(remote_variable, RubotoDialog, theme, &block)
|
67
77
|
end
|
68
78
|
|
69
|
-
|
70
|
-
|
79
|
+
def start_ruboto_activity(remote_variable, klass=RubotoActivity, theme=nil, &block)
|
80
|
+
$activity_init_block = block
|
71
81
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
82
|
+
if @initialized or self == $activity
|
83
|
+
b = Java::android.os.Bundle.new
|
84
|
+
b.putInt("Theme", theme) if theme
|
85
|
+
b.putString("Remote Variable", remote_variable)
|
86
|
+
b.putBoolean("Define Remote Variable", true)
|
87
|
+
b.putString("Initialize Script", "#{remote_variable}.initialize_activity")
|
76
88
|
|
77
|
-
|
78
|
-
|
79
|
-
|
89
|
+
i = Java::android.content.Intent.new
|
90
|
+
i.setClass self, klass.java_class
|
91
|
+
i.putExtra("RubotoActivity Config", b)
|
92
|
+
|
93
|
+
self.startActivity i
|
94
|
+
else
|
95
|
+
instance_eval "#{remote_variable}=self"
|
96
|
+
setRemoteVariable remote_variable
|
97
|
+
initialize_activity
|
98
|
+
on_create nil
|
99
|
+
end
|
100
|
+
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
#plugin
|
105
|
+
def toast(text, duration=5000)
|
106
|
+
Java::android.widget.Toast.makeText(self, text, duration).show
|
107
|
+
end
|
108
|
+
|
109
|
+
#plugin
|
110
|
+
def toast_result(result, success, failure, duration=5000)
|
111
|
+
toast(result ? success : failure, duration)
|
112
|
+
end
|
80
113
|
end
|
81
|
-
end
|
82
114
|
end
|
83
115
|
|
84
116
|
#############################################################################
|
@@ -138,7 +170,7 @@ def ruboto_configure_activity(klass)
|
|
138
170
|
def on_create(bundle)
|
139
171
|
@view_parent = nil
|
140
172
|
setContentView(instance_eval &@content_view_block) if @content_view_block
|
141
|
-
instance_eval {@finish_create_block.call} if @finish_create_block
|
173
|
+
instance_eval { @finish_create_block.call } if @finish_create_block
|
142
174
|
end
|
143
175
|
|
144
176
|
#
|
@@ -148,7 +180,7 @@ def ruboto_configure_activity(klass)
|
|
148
180
|
def add_menu title, icon=nil, &block
|
149
181
|
mi = @menu.add(title)
|
150
182
|
mi.setIcon(icon) if icon
|
151
|
-
mi.class.class_eval {attr_accessor :on_click}
|
183
|
+
mi.class.class_eval { attr_accessor :on_click }
|
152
184
|
mi.on_click = block
|
153
185
|
|
154
186
|
# Seems to be needed or the block might get cleaned up
|
@@ -158,14 +190,21 @@ def ruboto_configure_activity(klass)
|
|
158
190
|
|
159
191
|
def handle_create_options_menu &block
|
160
192
|
p = Proc.new do |*args|
|
161
|
-
@menu
|
162
|
-
instance_eval {block.call(*args)} if block
|
193
|
+
@menu = args[0]
|
194
|
+
instance_eval { block.call(*args) } if block
|
163
195
|
end
|
164
196
|
setCallbackProc(self.class.const_get("CB_CREATE_OPTIONS_MENU"), p)
|
165
197
|
|
166
|
-
p = Proc.new do |num,menu_item|
|
167
|
-
|
168
|
-
|
198
|
+
p = Proc.new do |num, menu_item|
|
199
|
+
# handles a problem where this is called for context items
|
200
|
+
# JRUBY-5866 JRuby can't access nested Java class if the class is called 'id'
|
201
|
+
unless @just_processed_context_item == menu_item || menu_item.item_id == JavaUtilities.get_proxy_class('android.R$id').home
|
202
|
+
instance_eval &(menu_item.on_click)
|
203
|
+
@just_processed_context_item = nil
|
204
|
+
true
|
205
|
+
else
|
206
|
+
false
|
207
|
+
end
|
169
208
|
end
|
170
209
|
setCallbackProc(self.class.const_get("CB_MENU_ITEM_SELECTED"), p)
|
171
210
|
end
|
@@ -176,7 +215,7 @@ def ruboto_configure_activity(klass)
|
|
176
215
|
|
177
216
|
def add_context_menu title, &block
|
178
217
|
mi = @context_menu.add(title)
|
179
|
-
mi.class.class_eval {attr_accessor :on_click}
|
218
|
+
mi.class.class_eval { attr_accessor :on_click }
|
180
219
|
mi.on_click = block
|
181
220
|
|
182
221
|
# Seems to be needed or the block might get cleaned up
|
@@ -186,14 +225,24 @@ def ruboto_configure_activity(klass)
|
|
186
225
|
|
187
226
|
def handle_create_context_menu &block
|
188
227
|
p = Proc.new do |*args|
|
189
|
-
@
|
190
|
-
instance_eval {block.call(*args)} if block
|
228
|
+
@context_menu = args[0]
|
229
|
+
instance_eval { block.call(*args) } if block
|
191
230
|
end
|
192
231
|
setCallbackProc(self.class.const_get("CB_CREATE_CONTEXT_MENU"), p)
|
193
232
|
|
194
233
|
p = Proc.new do |menu_item|
|
195
|
-
|
196
|
-
|
234
|
+
if menu_item.on_click
|
235
|
+
arg = menu_item
|
236
|
+
begin
|
237
|
+
arg = menu_item.getMenuInfo.position
|
238
|
+
rescue
|
239
|
+
end
|
240
|
+
instance_eval { menu_item.on_click.call(arg) }
|
241
|
+
@just_processed_context_item = menu_item
|
242
|
+
true
|
243
|
+
else
|
244
|
+
false
|
245
|
+
end
|
197
246
|
end
|
198
247
|
setCallbackProc(self.class.const_get("CB_CONTEXT_ITEM_SELECTED"), p)
|
199
248
|
end
|
@@ -212,14 +261,10 @@ def ruboto_setup(klass, init_method="create")
|
|
212
261
|
ruboto_allow_handlers(klass)
|
213
262
|
|
214
263
|
klass.class_eval do
|
215
|
-
def when_launched(&block)
|
216
|
-
instance_exec *args, &block
|
217
|
-
on_create nil
|
218
|
-
end
|
219
|
-
|
220
264
|
eval %Q{
|
221
265
|
def handle_#{init_method}(&block)
|
222
|
-
|
266
|
+
instance_exec &block
|
267
|
+
#{klass == Java::org.ruboto.RubotoActivity ? "on_create(nil)" : ""}
|
223
268
|
end
|
224
269
|
}
|
225
270
|
end
|
@@ -231,18 +276,43 @@ end
|
|
231
276
|
#
|
232
277
|
|
233
278
|
def ruboto_import_widgets(*widgets)
|
234
|
-
widgets.each{|i| ruboto_import_widget i}
|
279
|
+
widgets.each { |i| ruboto_import_widget i }
|
235
280
|
end
|
236
281
|
|
237
282
|
def ruboto_import_widget(class_name, package_name="android.widget")
|
238
283
|
view_class = java_import "#{package_name}.#{class_name}"
|
239
|
-
return unless view_class
|
240
284
|
|
241
285
|
RubotoActivity.class_eval "
|
242
|
-
def #{(class_name.to_s.gsub(/([A-Z])/) {'_' + $1.downcase})[1..-1]}(params={})
|
243
|
-
|
244
|
-
|
286
|
+
def #{(class_name.to_s.gsub(/([A-Z])/) { '_' + $1.downcase })[1..-1]}(params={})
|
287
|
+
force_style = params.delete(:default_style)
|
288
|
+
force_parent = params.delete(:parent)
|
289
|
+
force_index = params.delete(:parent_index)
|
290
|
+
if force_style
|
291
|
+
if params.any?
|
292
|
+
attributes = android.util.AttributeSet.impl do |method, *args|
|
293
|
+
puts 'Not implemented, yet.'
|
294
|
+
puts %Q{Unhandled AttributeSet method: \#{method}(\#{args.map{|a| a.inspect}.join(', ')})}
|
295
|
+
end
|
296
|
+
else
|
297
|
+
attributes = nil
|
298
|
+
end
|
299
|
+
rv = #{class_name}.new(self, attributes, force_style)
|
300
|
+
else
|
301
|
+
if api_key = params.delete(:apiKey)
|
302
|
+
rv = #{class_name}.new(self, api_key)
|
303
|
+
else
|
304
|
+
rv = #{class_name}.new(self)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
if force_index
|
309
|
+
(force_parent || @view_parent).addView(rv, force_index) if (force_parent || @view_parent)
|
310
|
+
else
|
311
|
+
(force_parent || @view_parent).addView(rv) if (force_parent || @view_parent)
|
312
|
+
end
|
313
|
+
|
245
314
|
rv.configure self, params
|
315
|
+
|
246
316
|
if block_given?
|
247
317
|
old_view_parent, @view_parent = @view_parent, rv
|
248
318
|
yield
|
@@ -252,9 +322,11 @@ def ruboto_import_widget(class_name, package_name="android.widget")
|
|
252
322
|
end
|
253
323
|
"
|
254
324
|
|
255
|
-
setup_list_view
|
256
|
-
|
257
|
-
|
325
|
+
setup_list_view if class_name == :ListView
|
326
|
+
setup_spinner if class_name == :Spinner
|
327
|
+
setup_button if class_name == :Button
|
328
|
+
setup_image_button if class_name == :ImageButton
|
329
|
+
setup_linear_layout if class_name == :LinearLayout
|
258
330
|
setup_relative_layout if class_name == :RelativeLayout
|
259
331
|
end
|
260
332
|
|
@@ -264,52 +336,52 @@ end
|
|
264
336
|
#
|
265
337
|
|
266
338
|
def setup_view
|
267
|
-
|
268
|
-
|
339
|
+
java_import "android.view.View"
|
340
|
+
java_import "android.view.ViewGroup"
|
269
341
|
|
270
|
-
|
271
|
-
|
342
|
+
View.class_eval do
|
343
|
+
@@convert_constants ||= {}
|
272
344
|
|
273
|
-
|
274
|
-
|
275
|
-
end
|
276
|
-
|
277
|
-
def self.convert_constant(from)
|
278
|
-
@@convert_constants[from] or from
|
279
|
-
end
|
280
|
-
|
281
|
-
def self.setup_constant_conversion
|
282
|
-
(self.constants - self.superclass.constants).each do |i|
|
283
|
-
View.add_constant_conversion i.downcase.to_sym, self.const_get(i)
|
345
|
+
def self.add_constant_conversion(from, to)
|
346
|
+
@@convert_constants[from] = to
|
284
347
|
end
|
285
|
-
end
|
286
348
|
|
287
|
-
|
288
|
-
|
289
|
-
getLayoutParams.width = View.convert_constant(width)
|
349
|
+
def self.convert_constant(from)
|
350
|
+
@@convert_constants[from] or from
|
290
351
|
end
|
291
352
|
|
292
|
-
|
293
|
-
|
353
|
+
def self.setup_constant_conversion
|
354
|
+
(self.constants - self.superclass.constants).each do |i|
|
355
|
+
View.add_constant_conversion i.downcase.to_sym, self.const_get(i)
|
356
|
+
end
|
294
357
|
end
|
295
358
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
359
|
+
def configure(context, params = {})
|
360
|
+
if width = params.delete(:width)
|
361
|
+
getLayoutParams.width = View.convert_constant(width)
|
362
|
+
end
|
363
|
+
|
364
|
+
if height = params.delete(:height)
|
365
|
+
getLayoutParams.height = View.convert_constant(height)
|
366
|
+
end
|
367
|
+
|
368
|
+
if layout = params.delete(:layout)
|
369
|
+
lp = getLayoutParams
|
370
|
+
layout.each do |k, v|
|
371
|
+
values = (v.is_a?(Array) ? v : [v]).map { |i| @@convert_constants[i] or i }
|
372
|
+
lp.send("#{k.to_s.gsub(/_([a-z])/) { $1.upcase }}", *values)
|
373
|
+
end
|
301
374
|
end
|
302
|
-
end
|
303
375
|
|
304
|
-
|
305
|
-
|
306
|
-
|
376
|
+
params.each do |k, v|
|
377
|
+
values = (v.is_a?(Array) ? v : [v]).map { |i| @@convert_constants[i] or i }
|
378
|
+
self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) { $2.upcase }}", *values)
|
379
|
+
end
|
307
380
|
end
|
308
381
|
end
|
309
|
-
end
|
310
382
|
|
311
|
-
|
312
|
-
|
383
|
+
View.add_constant_conversion :wrap_content, ViewGroup::LayoutParams::WRAP_CONTENT
|
384
|
+
View.add_constant_conversion :fill_parent, ViewGroup::LayoutParams::FILL_PARENT
|
313
385
|
end
|
314
386
|
|
315
387
|
#############################################################################
|
@@ -336,6 +408,17 @@ def setup_button
|
|
336
408
|
ruboto_register_handler("org.ruboto.callbacks.RubotoOnClickListener", "click", Button, "setOnClickListener")
|
337
409
|
end
|
338
410
|
|
411
|
+
def setup_image_button
|
412
|
+
ImageButton.class_eval do
|
413
|
+
def configure(context, params = {})
|
414
|
+
setOnClickListener(context)
|
415
|
+
super(context, params)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
ruboto_register_handler("org.ruboto.callbacks.RubotoOnClickListener", "click", ImageButton, "setOnClickListener")
|
420
|
+
end
|
421
|
+
|
339
422
|
def setup_list_view
|
340
423
|
ListView.class_eval do
|
341
424
|
attr_reader :adapter, :adapter_list
|
@@ -344,16 +427,20 @@ def setup_list_view
|
|
344
427
|
if params.has_key? :list
|
345
428
|
@adapter_list = Java::java.util.ArrayList.new
|
346
429
|
@adapter_list.addAll(params[:list])
|
347
|
-
|
430
|
+
item_layout = params.delete(:item_layout) || R::layout::simple_list_item_1
|
431
|
+
@adapter = Java::android.widget.ArrayAdapter.new(context, item_layout, @adapter_list)
|
348
432
|
setAdapter @adapter
|
349
433
|
params.delete :list
|
350
434
|
end
|
435
|
+
if params.has_key? :adapter
|
436
|
+
@adapter = params[:adapter]
|
437
|
+
end
|
351
438
|
setOnItemClickListener(context)
|
352
439
|
super(context, params)
|
353
440
|
end
|
354
441
|
|
355
442
|
def reload_list(list)
|
356
|
-
@adapter_list.clear
|
443
|
+
@adapter_list.clear
|
357
444
|
@adapter_list.addAll(list)
|
358
445
|
@adapter.notifyDataSetChanged
|
359
446
|
invalidate
|
@@ -363,6 +450,35 @@ def setup_list_view
|
|
363
450
|
ruboto_register_handler("org.ruboto.callbacks.RubotoOnItemClickListener", "item_click", ListView, "setOnItemClickListener")
|
364
451
|
end
|
365
452
|
|
453
|
+
def setup_spinner
|
454
|
+
Spinner.class_eval do
|
455
|
+
attr_reader :adapter, :adapter_list
|
456
|
+
|
457
|
+
def configure(context, params = {})
|
458
|
+
if params.has_key? :list
|
459
|
+
@adapter_list = Java::java.util.ArrayList.new
|
460
|
+
@adapter_list.addAll(params[:list])
|
461
|
+
item_layout = params.delete(:item_layout) || R::layout::simple_spinner_item
|
462
|
+
@adapter = Java::android.widget.ArrayAdapter.new(context, item_layout, @adapter_list)
|
463
|
+
@adapter.setDropDownViewResource(params.delete(:dropdown_layout) || R::layout::simple_spinner_dropdown_item)
|
464
|
+
setAdapter @adapter
|
465
|
+
params.delete :list
|
466
|
+
end
|
467
|
+
setOnItemSelectedListener(context)
|
468
|
+
super(context, params)
|
469
|
+
end
|
470
|
+
|
471
|
+
def reload_list(list)
|
472
|
+
@adapter.clear
|
473
|
+
@adapter.addAll(list)
|
474
|
+
@adapter.notifyDataSetChanged
|
475
|
+
invalidate
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
ruboto_register_handler("org.ruboto.callbacks.RubotoOnItemSelectedListener", "item_selected", Spinner, "setOnItemSelectedListener")
|
480
|
+
end
|
481
|
+
|
366
482
|
#############################################################################
|
367
483
|
#
|
368
484
|
# Import a class and set it up for handlers
|
@@ -378,31 +494,31 @@ end
|
|
378
494
|
#
|
379
495
|
# Allows RubotoActivity to handle callbacks covering Class based handlers
|
380
496
|
#
|
381
|
-
|
382
497
|
def ruboto_register_handler(handler_class, unique_name, for_class, method_name)
|
383
|
-
klass_name = handler_class[/.+\.([A-Z].+)/,1]
|
384
|
-
klass
|
385
|
-
return unless klass
|
386
|
-
|
387
|
-
RubotoActivity.class_eval "
|
388
|
-
attr_accessor :#{unique_name}_handler
|
498
|
+
klass_name = handler_class[/.+\.([A-Z].+)/, 1]
|
499
|
+
klass = ruboto_import handler_class
|
389
500
|
|
390
|
-
|
391
|
-
|
392
|
-
|
501
|
+
unless RubotoActivity.method_defined? "#{unique_name}_handler"
|
502
|
+
RubotoActivity.class_eval "
|
503
|
+
def #{unique_name}_handler
|
504
|
+
@#{unique_name}_handler ||= #{klass_name}.new
|
505
|
+
end
|
393
506
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
507
|
+
def handle_#{unique_name}(&block)
|
508
|
+
#{unique_name}_handler.handle_#{unique_name} &block
|
509
|
+
self
|
510
|
+
end
|
511
|
+
"
|
512
|
+
end
|
399
513
|
|
400
|
-
for_class.
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
514
|
+
unless for_class.method_defined? "orig_#{method_name}"
|
515
|
+
for_class.class_eval "
|
516
|
+
alias_method :orig_#{method_name}, :#{method_name}
|
517
|
+
def #{method_name}(handler)
|
518
|
+
orig_#{method_name}(handler.kind_of?(RubotoActivity) ? handler.#{unique_name}_handler : handler)
|
519
|
+
end
|
520
|
+
"
|
521
|
+
end
|
406
522
|
end
|
407
523
|
|
408
524
|
#############################################################################
|
@@ -411,7 +527,7 @@ end
|
|
411
527
|
#
|
412
528
|
|
413
529
|
def ruboto_import_preferences(*preferences)
|
414
|
-
preferences.each{|i| ruboto_import_preference i}
|
530
|
+
preferences.each { |i| ruboto_import_preference i }
|
415
531
|
end
|
416
532
|
|
417
533
|
def ruboto_import_preference(class_name, package_name="android.preference")
|
@@ -421,7 +537,7 @@ def ruboto_import_preference(class_name, package_name="android.preference")
|
|
421
537
|
setup_preferences
|
422
538
|
|
423
539
|
RubotoPreferenceActivity.class_eval "
|
424
|
-
def #{(class_name.to_s.gsub(/([A-Z])/) {'_' + $1.downcase})[1..-1]}(params={})
|
540
|
+
def #{(class_name.to_s.gsub(/([A-Z])/) { '_' + $1.downcase })[1..-1]}(params={})
|
425
541
|
rv = #{class_name}.new self
|
426
542
|
rv.configure self, params
|
427
543
|
@parent.addPreference(rv) if @parent
|
@@ -464,7 +580,7 @@ def setup_preferences
|
|
464
580
|
def on_create(bundle)
|
465
581
|
@parent = nil
|
466
582
|
setPreferenceScreen(instance_eval &@preference_screen_block) if @preference_screen_block
|
467
|
-
instance_eval {@finish_create_block.call} if @finish_create_block
|
583
|
+
instance_eval { @finish_create_block.call } if @finish_create_block
|
468
584
|
end
|
469
585
|
end
|
470
586
|
|
@@ -472,9 +588,9 @@ def setup_preferences
|
|
472
588
|
def configure(context, params = {})
|
473
589
|
params.each do |k, v|
|
474
590
|
if v.is_a?(Array)
|
475
|
-
self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) {$2.upcase}}", *v)
|
591
|
+
self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) { $2.upcase }}", *v)
|
476
592
|
else
|
477
|
-
self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) {$2.upcase}}", v)
|
593
|
+
self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) { $2.upcase }}", v)
|
478
594
|
end
|
479
595
|
end
|
480
596
|
end
|
@@ -488,22 +604,22 @@ end
|
|
488
604
|
#
|
489
605
|
# Final set up depending on globals
|
490
606
|
#
|
491
|
-
|
492
|
-
|
607
|
+
# TODO(uwe): I think ruboto.rb should not contain any conditions so it does not matter when it is required.
|
608
|
+
# TODO(uwe): Remove the commented lines after checking with Scott.
|
609
|
+
# if $activity
|
493
610
|
java_import "org.ruboto.RubotoActivity"
|
494
611
|
setup_activity
|
495
612
|
ruboto_configure_activity(RubotoActivity)
|
496
613
|
ruboto_setup(RubotoActivity)
|
497
614
|
setup_view
|
498
|
-
end
|
615
|
+
# end
|
499
616
|
|
500
|
-
if $service
|
617
|
+
# if $service
|
501
618
|
java_import "org.ruboto.RubotoService"
|
502
619
|
ruboto_setup(RubotoService)
|
503
|
-
end
|
620
|
+
# end
|
504
621
|
|
505
|
-
if $broadcast_receiver
|
622
|
+
# if $broadcast_receiver
|
506
623
|
java_import "org.ruboto.RubotoBroadcastReceiver"
|
507
624
|
ruboto_setup(RubotoBroadcastReceiver, "receive")
|
508
|
-
end
|
509
|
-
|
625
|
+
# end
|