ruboto 0.10.1 → 0.10.2.rc.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 (36) hide show
  1. data/Gemfile +1 -1
  2. data/Gemfile.lock +1 -1
  3. data/Rakefile +110 -34
  4. data/assets/rakelib/ruboto.rake +181 -76
  5. data/assets/src/org/ruboto/JRubyAdapter.java +7 -3
  6. data/assets/src/org/ruboto/ScriptLoader.java +12 -4
  7. data/assets/src/ruboto/widget.rb +43 -34
  8. data/bin/ruboto +9 -4
  9. data/lib/ruboto/sdk_versions.rb +11 -2
  10. data/lib/ruboto/util/build.rb +1 -1
  11. data/lib/ruboto/util/update.rb +104 -32
  12. data/lib/ruboto/version.rb +1 -1
  13. data/test/activity/call_super_activity.rb +2 -3
  14. data/test/activity/dir_and_file_activity.rb +18 -0
  15. data/test/activity/dir_and_file_activity_test.rb +20 -0
  16. data/test/activity/image_button_and_button_activity.rb +4 -5
  17. data/test/activity/json_activity.rb +21 -0
  18. data/test/activity/json_activity_test.rb +17 -0
  19. data/test/activity/location_activity.rb +30 -0
  20. data/test/activity/location_activity_test.rb +17 -0
  21. data/test/activity/margins_activity.rb +0 -1
  22. data/test/activity/option_menu_activity.rb +0 -1
  23. data/test/activity/psych_activity.rb +8 -2
  24. data/test/activity/ssl_activity.rb +31 -0
  25. data/test/activity/ssl_activity_test.rb +22 -0
  26. data/test/activity/stack_activity.rb +0 -1
  27. data/test/activity/stack_activity_test.rb +4 -5
  28. data/test/activity/subclass_activity.rb +0 -1
  29. data/test/activity/view_constants_activity.rb +0 -1
  30. data/test/app_test_methods.rb +19 -6
  31. data/test/minimal_app_test.rb +10 -10
  32. data/test/rake_test.rb +8 -8
  33. data/test/ruboto_gen_test.rb +18 -12
  34. data/test/ruboto_update_test.rb +16 -10
  35. data/test/test_helper.rb +16 -35
  36. metadata +21 -9
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gem 'rake'
4
4
  gem 'main'
data/Gemfile.lock CHANGED
@@ -1,5 +1,5 @@
1
1
  GEM
2
- remote: http://rubygems.org/
2
+ remote: https://rubygems.org/
3
3
  specs:
4
4
  arrayfields (4.7.4)
5
5
  chronic (0.6.7)
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ PLATFORM_PROJECT = File.expand_path('tmp/RubotoCore', File.dirname(__FILE__))
11
11
  PLATFORM_DEBUG_APK = "#{PLATFORM_PROJECT}/bin/RubotoCore-debug.apk"
12
12
  PLATFORM_DEBUG_APK_BAK = "#{PLATFORM_PROJECT}/bin/RubotoCore-debug.apk.bak"
13
13
  PLATFORM_RELEASE_APK = "#{PLATFORM_PROJECT}/bin/RubotoCore-release.apk"
14
- PLATFORM_CURRENT_RELEASE_APK = "#{PLATFORM_PROJECT}/bin/RubotoCore-release.apk.current"
14
+ PLATFORM_CURRENT_RELEASE_APK = File.expand_path('tmp/RubotoCore-release.apk', File.dirname(__FILE__))
15
15
  MANIFEST_FILE = "AndroidManifest.xml"
16
16
  GEM_FILE = "ruboto-#{Ruboto::VERSION}.gem"
17
17
  GEM_SPEC_FILE = 'ruboto.gemspec'
@@ -87,8 +87,8 @@ task :release_docs do
87
87
  user = ask('login : ') { |q| q.echo = true }
88
88
  pass = ask('password: ') { |q| q.echo = '*' }
89
89
  rescue
90
- print 'user name: ' ; user = STDIN.gets.chomp
91
- print ' password: ' ; pass = STDIN.gets.chomp
90
+ print 'user name: '; user = STDIN.gets.chomp
91
+ print ' password: '; pass = STDIN.gets.chomp
92
92
  end
93
93
  require 'uri'
94
94
  require 'net/http'
@@ -106,12 +106,12 @@ task :release_docs do
106
106
  req.basic_auth(user, pass)
107
107
  res = https.start { |http| http.request(req) }
108
108
  milestones = YAML.load(res.body).sort_by { |i| Date.parse(i['due_on']) }
109
- puts milestones.map{|m| "#{'%2d' % m['number']} #{m['title']}"}.join("\n")
109
+ puts milestones.map { |m| "#{'%2d' % m['number']} #{m['title']}" }.join("\n")
110
110
 
111
111
  if defined? ask
112
112
  milestone = ask('milestone: ', Integer) { |q| q.echo = true }
113
113
  else
114
- print 'milestone: ' ; milestone = STDIN.gets.chomp
114
+ print 'milestone: '; milestone = STDIN.gets.chomp
115
115
  end
116
116
 
117
117
  uri = URI("#{base_uri}/issues?milestone=#{milestone}&state=closed&per_page=1000")
@@ -123,9 +123,9 @@ task :release_docs do
123
123
  milestone_description = issues[0] ? issues[0]['milestone']['description'] : "No issues for milestone #{milestone}"
124
124
  categories = {'Features' => 'feature', 'Bugfixes' => 'bug', 'Internal' => 'internal', 'Support' => 'support', 'Documentation' => 'documentation', 'Pull requests' => nil, 'Other' => nil}
125
125
  grouped_issues = issues.group_by do |i|
126
- labels = i['labels'].map { |l| l['name']}
126
+ labels = i['labels'].map { |l| l['name'] }
127
127
  cat = nil
128
- categories.each do |k,v|
128
+ categories.each do |k, v|
129
129
  if labels.include? v
130
130
  cat = k
131
131
  break
@@ -198,7 +198,7 @@ task :stats do
198
198
  https.use_ssl = true
199
199
  https.verify_mode = OpenSSL::SSL::VERIFY_NONE
200
200
 
201
- counts_per_month = Hash.new{|h, k| h[k] = Hash.new{|mh,mk| mh[mk] = 0 }}
201
+ counts_per_month = Hash.new { |h, k| h[k] = Hash.new { |mh, mk| mh[mk] = 0 } }
202
202
  total = 0
203
203
 
204
204
  %w{ruboto-core ruboto}.each do |gem|
@@ -213,20 +213,20 @@ task :stats do
213
213
  req = Net::HTTP::Get.new(downloads_uri.request_uri)
214
214
  res = https.start { |http| http.request(req) }
215
215
  counts = YAML.load(res.body)
216
- counts.delete_if{|date_str,count| count == 0}
216
+ counts.delete_if { |date_str, count| count == 0 }
217
217
  counts.each do |date_str, count|
218
218
  date = Date.parse(date_str)
219
219
  counts_per_month[date.year][date.month] += count
220
220
  total += count
221
221
  end
222
- print '.' ; STDOUT.flush
222
+ print '.'; STDOUT.flush
223
223
  end
224
224
  puts
225
225
  end
226
226
 
227
227
  puts "\nDownloads statistics per month:"
228
228
  years = counts_per_month.keys
229
- puts "\n #{years.map{|year| '%6s:' % year}.join(' ')}"
229
+ puts "\n #{years.map { |year| '%6s:' % year }.join(' ')}"
230
230
  (1..12).each do |month|
231
231
  print "#{'%2d' % month}:"
232
232
  years.each do |year|
@@ -240,7 +240,7 @@ task :stats do
240
240
 
241
241
  puts "\nRubyGems download statistics per month:"
242
242
  years = counts_per_month.keys
243
- puts ' ' + years.map{|year| '%-12s' % year}.join
243
+ puts ' ' + years.map { |year| '%-12s' % year }.join
244
244
  (0..20).each do |l|
245
245
  print (l % 10 == 0) ? '%4d' % ((20-l) * 100) : ' '
246
246
  years.each do |year|
@@ -254,7 +254,7 @@ task :stats do
254
254
  end
255
255
  puts
256
256
  end
257
- puts ' ' + years.map{|year| '%-12s' % year}.join
257
+ puts ' ' + years.map { |year| '%-12s' % year }.join
258
258
 
259
259
  puts "\nTotal: #{total}\n\n"
260
260
  end
@@ -275,11 +275,15 @@ task :release => [:clean, :gem] do
275
275
  sh "git push"
276
276
  end
277
277
 
278
- desc "Run the tests"
278
+ desc "Run the tests. Select which test files to load with 'rake test TEST=test_file_pattern'"
279
279
  task :test do
280
280
  FileUtils.rm_rf Dir['tmp/RubotoTestApp_template*']
281
- Dir['./test/*_test.rb'].each do |f|
282
- require f.chomp('.rb')
281
+ test_pattern = ARGV.grep(/^TEST=.*$/)
282
+ ARGV.delete_if { |a| test_pattern.include? a }
283
+ test_pattern.map! { |t| t[5..-1] }
284
+ $: << File.expand_path('test', File.dirname(__FILE__))
285
+ (test_pattern.any? ? test_pattern : ['test/*_test.rb']).map { |d| Dir[d] }.flatten.each do |f|
286
+ require f.chomp('.rb')[5..-1]
283
287
  end
284
288
  end
285
289
 
@@ -305,13 +309,10 @@ namespace :platform do
305
309
  task PLATFORM_DEBUG_APK do
306
310
  Rake::Task[PLATFORM_PROJECT].invoke
307
311
  Dir.chdir(PLATFORM_PROJECT) do
308
- if File.exists?(PLATFORM_CURRENT_RELEASE_APK) && File.exists?(PLATFORM_DEBUG_APK) &&
309
- File.size(PLATFORM_CURRENT_RELEASE_APK) == File.size(PLATFORM_DEBUG_APK)
310
- if File.exists?(PLATFORM_DEBUG_APK_BAK)
311
- FileUtils.cp PLATFORM_DEBUG_APK_BAK, PLATFORM_DEBUG_APK
312
- else
313
- FileUtils.rm PLATFORM_DEBUG_APK
314
- end
312
+ if File.exists?(PLATFORM_DEBUG_APK_BAK)
313
+ FileUtils.cp PLATFORM_DEBUG_APK_BAK, PLATFORM_DEBUG_APK
314
+ else
315
+ FileUtils.rm PLATFORM_DEBUG_APK
315
316
  end
316
317
  sh 'rake debug'
317
318
  end
@@ -342,14 +343,9 @@ namespace :platform do
342
343
  end
343
344
  end
344
345
 
345
- desc 'Use the current RubotoCore platform release apk'
346
- task :current => [:debug, PLATFORM_CURRENT_RELEASE_APK] do
347
- Dir.chdir PLATFORM_PROJECT do
348
- if File.size(PLATFORM_CURRENT_RELEASE_APK) != File.size(PLATFORM_DEBUG_APK)
349
- FileUtils.cp PLATFORM_DEBUG_APK, PLATFORM_DEBUG_APK_BAK
350
- FileUtils.cp PLATFORM_CURRENT_RELEASE_APK, PLATFORM_DEBUG_APK
351
- end
352
- end
346
+ desc 'Install the current RubotoCore platform release apk'
347
+ task :current => PLATFORM_CURRENT_RELEASE_APK do
348
+ install_apk
353
349
  end
354
350
 
355
351
  desc 'Install the Ruboto Core platform debug apk'
@@ -360,9 +356,89 @@ namespace :platform do
360
356
  end
361
357
 
362
358
  desc 'Uninstall the Ruboto Core platform debug apk'
363
- task :uninstall => PLATFORM_PROJECT do
364
- Dir.chdir(PLATFORM_PROJECT) do
365
- sh 'rake uninstall'
359
+ task :uninstall do
360
+ uninstall_apk
361
+ end
362
+
363
+ private
364
+
365
+ def package
366
+ 'org.ruboto.core'
367
+ end
368
+
369
+ def install_apk
370
+ failure_pattern = /^Failure \[(.*)\]/
371
+ success_pattern = /^Success/
372
+ case package_installed?
373
+ when true
374
+ puts "Package #{package} already installed."
375
+ return
376
+ when false
377
+ puts "Package #{package} already installed, but of different size. Replacing package."
378
+ output = `adb install -r #{PLATFORM_CURRENT_RELEASE_APK} 2>&1`
379
+ if $? == 0 && output !~ failure_pattern && output =~ success_pattern
380
+ clear_update
381
+ return
382
+ end
383
+ case $1
384
+ when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
385
+ puts 'Found package signed with different certificate. Uninstalling it and retrying install.'
386
+ else
387
+ puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
388
+ puts "Uninstalling #{package} and retrying install."
389
+ end
390
+ uninstall_apk
391
+ end
392
+ puts "Installing package #{package}"
393
+ begin
394
+ output = nil
395
+ timeout 180 do
396
+ output = `adb install #{PLATFORM_CURRENT_RELEASE_APK} 2>&1`
397
+ end
398
+ rescue TimeoutError
399
+ puts 'Install of current RubotoCore timed out. Retrying.'
400
+ retry
401
+ end
402
+ puts output
403
+ raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
404
+ end
405
+
406
+ def uninstall_apk
407
+ return if package_installed?.nil?
408
+ puts "Uninstalling package #{package}"
409
+ system "adb uninstall #{package}"
410
+ if $? != 0 && package_installed?
411
+ puts "Uninstall failed exit code #{$?}"
412
+ exit $?
366
413
  end
367
414
  end
415
+
416
+ def package_installed?
417
+ package_name = package
418
+ ['', '-0', '-1', '-2'].each do |i|
419
+ path = "/data/app/#{package_name}#{i}.apk"
420
+ o = `adb shell ls -l #{path}`.chomp
421
+ if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(path)}$/
422
+ apk_file = PLATFORM_CURRENT_RELEASE_APK
423
+ if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
424
+ return true
425
+ else
426
+ return false
427
+ end
428
+ end
429
+
430
+ sdcard_path = "/mnt/asec/#{package_name}#{i}/pkg.apk"
431
+ o = `adb shell ls -l #{sdcard_path}`.chomp
432
+ if o =~ /^-r-xr-xr-x system\s+root\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(sdcard_path)}$/
433
+ apk_file = PLATFORM_CURRENT_RELEASE_APK
434
+ if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
435
+ return true
436
+ else
437
+ return false
438
+ end
439
+ end
440
+ end
441
+ return nil
442
+ end
443
+
368
444
  end
@@ -3,8 +3,11 @@ require 'rubygems'
3
3
  require 'time'
4
4
  require 'rake/clean'
5
5
  require 'rexml/document'
6
+ require 'timeout'
6
7
 
7
- ANT_CMD = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/i) ? "ant.bat" : "ant"
8
+ ON_WINDOWS = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/i)
9
+
10
+ ANT_CMD = ON_WINDOWS ? 'ant.bat' : 'ant'
8
11
 
9
12
  if `#{ANT_CMD} -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.to_i == 1 && $2.to_i < 8)
10
13
  puts "ANT version 1.8.0 or later required. Version found: #{$1}.#{$2}.#{$3}"
@@ -12,48 +15,64 @@ if `#{ANT_CMD} -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.
12
15
  end
13
16
 
14
17
  adb_version_str = `adb version`
15
- (puts "Android SDK platform tools not in PATH (adb command not found).";exit 1) unless $? == 0
16
- (puts "Unrecognized adb version: #$1";exit 1) unless adb_version_str =~ /Android Debug Bridge version (\d+\.\d+\.\d+)/
17
- (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')
18
- adb_path = `which adb`
19
- ENV['ANDROID_HOME'] ||= File.dirname(File.dirname(adb_path)) if $? == 0
20
-
21
- dx_filename = "#{ENV['ANDROID_HOME']}/platform-tools/dx"
22
- old_dx_content = File.read(dx_filename)
23
- new_dx_content = old_dx_content.dup
24
- if new_dx_content =~ /^defaultMx="-Xmx(\d+)(M|G)"/ &&
25
- ($1.to_i * 1024 ** {'M' => 2, 'G' => 3, 'T' => 4}[$2]) < 3*1024**3
26
- new_dx_content.sub(/^defaultMx="-Xmx\d+(M|G)"/, 'defaultMx="-Xmx3G"')
27
- File.open(dx_filename, 'w') { |f| f << new_dx_content }
28
- end
29
-
30
- def manifest() @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
31
- def package() manifest.root.attribute('package') end
32
- def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
33
- def scripts_path() @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
34
- def app_files_path() @app_files_path ||= "/data/data/#{package}/files" end
35
-
36
- PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
18
+ (puts 'Android SDK platform tools not in PATH (adb command not found).'; exit 1) unless $? == 0
19
+ (puts "Unrecognized adb version: #$1"; exit 1) unless adb_version_str =~ /Android Debug Bridge version (\d+\.\d+\.\d+)/
20
+ (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')
21
+ unless ENV['ANDROID_HOME']
22
+ unless ON_WINDOWS
23
+ begin
24
+ adb_path = `which adb`
25
+ ENV['ANDROID_HOME'] = File.dirname(File.dirname(adb_path)) if $? == 0
26
+ rescue Errno::ENOENT
27
+ puts "Unable to detect adb location: #$!"
28
+ end
29
+ end
30
+ end
31
+ (puts 'You need to set the ANDROID_HOME environment variable.'; exit 1) unless ENV['ANDROID_HOME']
32
+
33
+ # FIXME(uwe): On windows the file is called dx.bat
34
+ dx_filename = File.join(ENV['ANDROID_HOME'], 'platform-tools', ON_WINDOWS ? 'dx.bat' : 'dx')
35
+ unless File.exists? dx_filename
36
+ puts 'You need to install the Android SDK Platform-tools!'
37
+ exit 1
38
+ end
39
+ new_dx_content = File.read(dx_filename).dup
40
+ # set defaultXmx=-Xmx1024M
41
+ xmx_pattern = /^defaultMx="-Xmx(\d+)(M|m|G|g|T|t)"/
42
+ if new_dx_content =~ xmx_pattern &&
43
+ ($1.to_i * 1024 ** {'M' => 2, 'G' => 3, 'T' => 4}[$2.upcase]) < 2560*1024**2
44
+ puts "Increasing max heap space from #$1#$2 to 2560M in #{dx_filename}"
45
+ new_dx_content.sub!(xmx_pattern, 'defaultMx="-Xmx2560M"')
46
+ File.open(dx_filename, 'w') { |f| f << new_dx_content } rescue puts "\n!!! Unable to increase dx heap size !!!\n\n"
47
+ end
48
+
49
+ def manifest; @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
50
+ def package; manifest.root.attribute('package') end
51
+ def build_project_name; @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
52
+ def scripts_path; @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
53
+ def app_files_path; @app_files_path ||= "/data/data/#{package}/files" end
54
+
55
+ PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
37
56
  UPDATE_MARKER_FILE = File.join(PROJECT_DIR, 'bin', 'LAST_UPDATE')
38
- BUNDLE_JAR = File.expand_path 'libs/bundle.jar'
39
- BUNDLE_PATH = File.expand_path 'bin/bundle'
40
- MANIFEST_FILE = File.expand_path 'AndroidManifest.xml'
57
+ BUNDLE_JAR = File.expand_path 'libs/bundle.jar'
58
+ BUNDLE_PATH = File.expand_path 'bin/bundle'
59
+ MANIFEST_FILE = File.expand_path 'AndroidManifest.xml'
41
60
  PROJECT_PROPS_FILE = File.expand_path 'project.properties'
42
61
  RUBOTO_CONFIG_FILE = File.expand_path 'ruboto.yml'
43
- GEM_FILE = File.expand_path('Gemfile.apk')
44
- GEM_LOCK_FILE = File.expand_path('Gemfile.apk.lock')
45
- RELEASE_APK_FILE = File.expand_path "bin/#{build_project_name}-release.apk"
46
- APK_FILE = File.expand_path "bin/#{build_project_name}-debug.apk"
47
- TEST_APK_FILE = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
48
- JRUBY_JARS = Dir[File.expand_path 'libs/jruby-*.jar']
49
- RESOURCE_FILES = Dir[File.expand_path 'res/**/*']
50
- JAVA_SOURCE_FILES = Dir[File.expand_path 'src/**/*.java']
51
- RUBY_SOURCE_FILES = Dir[File.expand_path 'src/**/*.rb']
52
- APK_DEPENDENCIES = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
53
- KEYSTORE_FILE = (key_store = File.readlines('ant.properties').grep(/^key.store=/).first) ? File.expand_path(key_store.chomp.sub(/^key.store=/, '').sub('${user.home}', '~')) : "#{build_project_name}.keystore"
54
- KEYSTORE_ALIAS = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
55
-
56
- CLEAN.include('bin', 'gen')
62
+ GEM_FILE = File.expand_path 'Gemfile.apk'
63
+ GEM_LOCK_FILE = File.expand_path 'Gemfile.apk.lock'
64
+ RELEASE_APK_FILE = File.expand_path "bin/#{build_project_name}-release.apk"
65
+ APK_FILE = File.expand_path "bin/#{build_project_name}-debug.apk"
66
+ TEST_APK_FILE = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
67
+ JRUBY_JARS = Dir[File.expand_path 'libs/jruby-*.jar']
68
+ RESOURCE_FILES = Dir[File.expand_path 'res/**/*']
69
+ JAVA_SOURCE_FILES = Dir[File.expand_path 'src/**/*.java']
70
+ RUBY_SOURCE_FILES = Dir[File.expand_path 'src/**/*.rb']
71
+ APK_DEPENDENCIES = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
72
+ KEYSTORE_FILE = (key_store = File.readlines('ant.properties').grep(/^key.store=/).first) ? File.expand_path(key_store.chomp.sub(/^key.store=/, '').sub('${user.home}', '~')) : "#{build_project_name}.keystore"
73
+ KEYSTORE_ALIAS = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
74
+
75
+ CLEAN.include('bin', 'gen', 'test/bin', 'test/gen')
57
76
 
58
77
  task :default => :debug
59
78
 
@@ -84,7 +103,7 @@ namespace :debug do
84
103
  end
85
104
  end
86
105
 
87
- desc "build package and install it on the emulator or device"
106
+ desc 'build package and install it on the emulator or device'
88
107
  task :install => APK_FILE do
89
108
  install_apk
90
109
  end
@@ -117,10 +136,10 @@ task :keystore => KEYSTORE_FILE
117
136
 
118
137
  file KEYSTORE_FILE do
119
138
  unless File.read('ant.properties') =~ /^key.store=/
120
- File.open('ant.properties', 'a'){|f| f << "\nkey.store=#{KEYSTORE_FILE}\n"}
139
+ File.open('ant.properties', 'a') { |f| f << "\nkey.store=#{KEYSTORE_FILE}\n" }
121
140
  end
122
141
  unless File.read('ant.properties') =~ /^key.alias=/
123
- File.open('ant.properties', 'a'){|f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n"}
142
+ File.open('ant.properties', 'a') { |f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n" }
124
143
  end
125
144
  sh "keytool -genkey -v -keystore #{KEYSTORE_FILE} -alias #{KEYSTORE_ALIAS} -keyalg RSA -keysize 2048 -validity 10000"
126
145
  end
@@ -129,14 +148,14 @@ desc 'Tag this working copy with the current version'
129
148
  task :tag do
130
149
  next unless File.exists?('.git') && `git --version` =~ /git version /
131
150
  unless `git branch` =~ /^\* master$/
132
- puts "You must be on the master branch to release!"
151
+ puts 'You must be on the master branch to release!'
133
152
  exit!
134
153
  end
135
154
  # sh "git commit --allow-empty -a -m 'Release #{version}'"
136
155
  output = `git status --porcelain`
137
156
  raise "\nWorkspace not clean!\n#{output}" unless output.empty?
138
157
  sh "git tag #{version}"
139
- sh "git push origin master --tags"
158
+ sh 'git push origin master --tags'
140
159
  end
141
160
 
142
161
  desc 'Start the emulator with larger disk'
@@ -151,7 +170,7 @@ end
151
170
 
152
171
  desc 'Stop the application on the device/emulator (requires emulator or rooted device).'
153
172
  task :stop do
154
- raise "Unable to stop app. Only available on emulator." unless stop_app
173
+ raise 'Unable to stop app. Only available on emulator.' unless stop_app
155
174
  end
156
175
 
157
176
  desc 'Restart the application'
@@ -166,9 +185,9 @@ file MANIFEST_FILE => PROJECT_PROPS_FILE do
166
185
  sdk_level = File.read(PROJECT_PROPS_FILE).scan(/(?:target=android-)(\d+)/)[0][0].to_i
167
186
  old_manifest = File.read(MANIFEST_FILE)
168
187
  manifest = old_manifest.dup
169
- manifest.sub!(/(android:minSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
170
- manifest.sub!(/(android:targetSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
171
- File.open(MANIFEST_FILE, 'w'){|f| f << manifest} if manifest != old_manifest
188
+ manifest.sub!(/(android:minSdkVersion=').*?(')/) { "#$1#{sdk_level}#$2" }
189
+ manifest.sub!(/(android:targetSdkVersion=').*?(')/) { "#$1#{sdk_level}#$2" }
190
+ File.open(MANIFEST_FILE, 'w') { |f| f << manifest } if manifest != old_manifest
172
191
  end
173
192
 
174
193
  file RUBOTO_CONFIG_FILE
@@ -178,7 +197,7 @@ file APK_FILE => APK_DEPENDENCIES do |t|
178
197
  end
179
198
 
180
199
  desc 'Copy scripts to emulator or device'
181
- task :update_scripts => ['install:quick'] do
200
+ task :update_scripts => %w(install:quick) do
182
201
  update_scripts
183
202
  end
184
203
 
@@ -206,7 +225,23 @@ namespace :test do
206
225
  task :quick => :update_scripts do
207
226
  Dir.chdir('test') do
208
227
  puts 'Running quick tests'
209
- sh "#{ANT_CMD} instrument install run-tests-quick"
228
+ sh "#{ANT_CMD} instrument"
229
+ install_retry_count = 0
230
+ begin
231
+ timeout 120 do
232
+ sh "#{ANT_CMD} installi"
233
+ end
234
+ rescue TimeoutError
235
+ puts 'Installing package timed out.'
236
+ install_retry_count += 1
237
+ if install_retry_count > 3
238
+ puts 'Retrying install...'
239
+ retry
240
+ end
241
+ puts 'Trying one final time to install the package:'
242
+ sh "#{ANT_CMD} installi"
243
+ end
244
+ sh "#{ANT_CMD} run-tests-quick"
210
245
  end
211
246
  end
212
247
  end
@@ -221,11 +256,26 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
221
256
  next unless File.exists? GEM_FILE
222
257
  puts "Generating #{BUNDLE_JAR}"
223
258
 
224
- FileUtils.mkdir_p BUNDLE_PATH
225
- sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH}"
259
+ # Override RUBY_ENGINE (we can bundle from MRI for JRuby)
260
+ platforms = Gem.platforms
261
+ ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
262
+ Gem.platforms = [Gem::Platform::RUBY, Gem::Platform.new('universal-java')]
263
+ Object.const_set('RUBY_ENGINE', 'jruby')
264
+
265
+ ENV['BUNDLE_GEMFILE'] = GEM_FILE
266
+ require 'bundler'
267
+ Bundler.bundle_path = Pathname.new BUNDLE_PATH
268
+
269
+ definition = Bundler.definition
270
+ definition.validate_ruby!
271
+ Bundler::Installer.install(Bundler.root, definition)
272
+
273
+ # Restore RUBY_ENGINE (limit the scope of this hack)
274
+ Object.const_set('RUBY_ENGINE', ruby_engine) if ruby_engine
275
+ Gem.platforms = platforms
226
276
 
227
- gem_paths = Dir["#{BUNDLE_PATH}/{{,j}ruby,rbx}/{1.8,1.9{,.1},shared}/gems"]
228
- raise "Gem path not found" if gem_paths.empty?
277
+ gem_paths = Dir["#{BUNDLE_PATH}/gems"]
278
+ raise 'Gem path not found' if gem_paths.empty?
229
279
  raise "Found multiple gem paths: #{gem_paths}" if gem_paths.size > 1
230
280
  gem_path = gem_paths[0]
231
281
  puts "Found gems in #{gem_path}"
@@ -257,11 +307,11 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
257
307
  Dir.chdir gem_path do
258
308
  scanned_files = []
259
309
  source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
260
- Dir["*/lib/**/*"].each do |f|
310
+ Dir['*/lib/**/*'].each do |f|
261
311
  next if File.directory? f
262
- raise "Malformed file name" unless f =~ %r{^(.*?)/lib/(.*)$}
312
+ raise 'Malformed file name' unless f =~ %r{^(.*?)/lib/(.*)$}
263
313
  gem_name, lib_file = $1, $2
264
- if existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} }
314
+ if (existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} })
265
315
  puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
266
316
  FileUtils.rm existing_file
267
317
  scanned_files.delete existing_file
@@ -300,6 +350,20 @@ puts 'Starting JRuby OpenSSL Service'
300
350
  public
301
351
  Java::JopensslService.new.basicLoad(JRuby.runtime)
302
352
  END_CODE
353
+ elsif jar =~ %r{json/ext/generator.jar$}
354
+ jar_load_code = <<-END_CODE
355
+ require 'jruby'
356
+ puts 'Starting JSON Generator Service'
357
+ public
358
+ Java::json.ext.GeneratorService.new.basicLoad(JRuby.runtime)
359
+ END_CODE
360
+ elsif jar =~ %r{json/ext/parser.jar$}
361
+ jar_load_code = <<-END_CODE
362
+ require 'jruby'
363
+ puts 'Starting JSON Parser Service'
364
+ public
365
+ Java::json.ext.ParserService.new.basicLoad(JRuby.runtime)
366
+ END_CODE
303
367
  else
304
368
  jar_load_code = ''
305
369
  end
@@ -345,7 +409,7 @@ def strings(name)
345
409
  end
346
410
 
347
411
  def version
348
- strings :version_name
412
+ manifest.root.attribute('versionName')
349
413
  end
350
414
 
351
415
  def app_name
@@ -358,18 +422,24 @@ end
358
422
 
359
423
  def device_path_exists?(path)
360
424
  path_output =`adb shell ls #{path}`
361
- result = path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
362
- result
425
+ path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
363
426
  end
364
427
 
365
- def package_installed? test = false
428
+ # Determine if the package is installed.
429
+ # Return true if the package is installed and is identical to the local package.
430
+ # Return false if the package is installed, but differs from the local package.
431
+ # Return nil if the package is not installed.
432
+ def package_installed?(test = false)
366
433
  package_name = "#{package}#{'.tests' if test}"
367
- ['', '-0', '-1', '-2'].each do |i|
434
+ %w( -0 -1 -2).each do |i|
368
435
  path = "/data/app/#{package_name}#{i}.apk"
369
436
  o = `adb shell ls -l #{path}`.chomp
370
- if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(path)}$/
437
+ if o =~ /^-rw-r--r-- system\s+system\s+(\d+)\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2})\s+#{File.basename(path)}$/
438
+ installed_apk_size = $1.to_i
439
+ installed_timestamp = Time.parse($2)
371
440
  apk_file = test ? TEST_APK_FILE : APK_FILE
372
- if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
441
+ if !File.exists?(apk_file) || (installed_apk_size == File.size(apk_file) &&
442
+ installed_timestamp >= File.mtime(apk_file))
373
443
  return true
374
444
  else
375
445
  return false
@@ -378,16 +448,19 @@ def package_installed? test = false
378
448
 
379
449
  sdcard_path = "/mnt/asec/#{package_name}#{i}/pkg.apk"
380
450
  o = `adb shell ls -l #{sdcard_path}`.chomp
381
- if o =~ /^-r-xr-xr-x system\s+root\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(sdcard_path)}$/
451
+ if o =~ /^-r-xr-xr-x system\s+root\s+(\d+)\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2})\s+#{File.basename(sdcard_path)}$/
452
+ installed_apk_size = $1.to_i
453
+ installed_timestamp = Time.parse($2)
382
454
  apk_file = test ? TEST_APK_FILE : APK_FILE
383
- if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
455
+ if !File.exists?(apk_file) || (installed_apk_size == File.size(apk_file) &&
456
+ installed_timestamp >= File.mtime(apk_file))
384
457
  return true
385
458
  else
386
459
  return false
387
460
  end
388
461
  end
389
462
  end
390
- return nil
463
+ nil
391
464
  end
392
465
 
393
466
  def replace_faulty_code(faulty_file, faulty_code)
@@ -420,7 +493,7 @@ def build_apk(t, release)
420
493
  else
421
494
  sh "#{ANT_CMD} debug"
422
495
  end
423
- return true
496
+ true
424
497
  end
425
498
 
426
499
  def install_apk
@@ -431,23 +504,55 @@ def install_apk
431
504
  puts "Package #{package} already installed."
432
505
  return
433
506
  when false
434
- puts "Package #{package} already installed, but of different size. Replacing package."
435
- output = `adb install -r #{APK_FILE} 2>&1`
507
+ puts "Package #{package} already installed, but of different size or timestamp. Replacing package."
508
+ output = nil
509
+ install_retry_count = 0
510
+ begin
511
+ timeout 120 do
512
+ output = `adb install -r #{APK_FILE} 2>&1`
513
+ end
514
+ rescue Timeout::Error
515
+ puts "Installing package #{package} timed out."
516
+ install_retry_count += 1
517
+ if install_retry_count > 3
518
+ puts 'Retrying install...'
519
+ retry
520
+ end
521
+ puts 'Trying one final time to install the package:'
522
+ output = `adb install -r #{APK_FILE} 2>&1`
523
+ end
436
524
  if $? == 0 && output !~ failure_pattern && output =~ success_pattern
437
525
  clear_update
438
526
  return
439
527
  end
440
528
  case $1
441
529
  when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
442
- puts "Found package signed with different certificate. Uninstalling it and retrying install."
530
+ puts 'Found package signed with different certificate. Uninstalling it and retrying install.'
443
531
  else
444
532
  puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
445
533
  puts "Uninstalling #{package} and retrying install."
446
534
  end
447
535
  uninstall_apk
536
+ else
537
+ # Package not installed.
448
538
  end
449
539
  puts "Installing package #{package}"
450
- output = `adb install #{APK_FILE} 2>&1`
540
+ output = nil
541
+ install_retry_count = 0
542
+ begin
543
+ timeout 120 do
544
+ output = `adb install #{APK_FILE} 2>&1`
545
+ end
546
+ rescue Timeout::Error
547
+ puts "Installing package #{package} timed out."
548
+ install_retry_count += 1
549
+ if install_retry_count > 3
550
+ puts 'Retrying install...'
551
+ retry
552
+ end
553
+ puts 'Trying one final time to install the package:'
554
+ output = `adb install #{APK_FILE} 2>&1`
555
+ end
451
556
  puts output
452
557
  raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
453
558
  clear_update
@@ -465,10 +570,10 @@ end
465
570
 
466
571
  def update_scripts
467
572
  `adb shell mkdir -p #{scripts_path}` if !device_path_exists?(scripts_path)
468
- puts "Pushing files to apk public file area."
573
+ puts 'Pushing files to apk public file area.'
469
574
  last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
470
575
  Dir.chdir('src') do
471
- Dir["**/*.rb"].each do |script_file|
576
+ Dir['**/*.rb'].each do |script_file|
472
577
  next if File.directory? script_file
473
578
  next if File.mtime(script_file) < last_update
474
579
  next if script_file =~ /~$/
@@ -485,5 +590,5 @@ end
485
590
 
486
591
  def stop_app
487
592
  output = `adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
488
- return output !~ /Operation not permitted/
593
+ output !~ /Operation not permitted/
489
594
  end