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.
- data/Gemfile +1 -1
- data/Gemfile.lock +1 -1
- data/Rakefile +110 -34
- data/assets/rakelib/ruboto.rake +181 -76
- data/assets/src/org/ruboto/JRubyAdapter.java +7 -3
- data/assets/src/org/ruboto/ScriptLoader.java +12 -4
- data/assets/src/ruboto/widget.rb +43 -34
- data/bin/ruboto +9 -4
- data/lib/ruboto/sdk_versions.rb +11 -2
- data/lib/ruboto/util/build.rb +1 -1
- data/lib/ruboto/util/update.rb +104 -32
- data/lib/ruboto/version.rb +1 -1
- data/test/activity/call_super_activity.rb +2 -3
- data/test/activity/dir_and_file_activity.rb +18 -0
- data/test/activity/dir_and_file_activity_test.rb +20 -0
- data/test/activity/image_button_and_button_activity.rb +4 -5
- data/test/activity/json_activity.rb +21 -0
- data/test/activity/json_activity_test.rb +17 -0
- data/test/activity/location_activity.rb +30 -0
- data/test/activity/location_activity_test.rb +17 -0
- data/test/activity/margins_activity.rb +0 -1
- data/test/activity/option_menu_activity.rb +0 -1
- data/test/activity/psych_activity.rb +8 -2
- data/test/activity/ssl_activity.rb +31 -0
- data/test/activity/ssl_activity_test.rb +22 -0
- data/test/activity/stack_activity.rb +0 -1
- data/test/activity/stack_activity_test.rb +4 -5
- data/test/activity/subclass_activity.rb +0 -1
- data/test/activity/view_constants_activity.rb +0 -1
- data/test/app_test_methods.rb +19 -6
- data/test/minimal_app_test.rb +10 -10
- data/test/rake_test.rb +8 -8
- data/test/ruboto_gen_test.rb +18 -12
- data/test/ruboto_update_test.rb +16 -10
- data/test/test_helper.rb +16 -35
- metadata +21 -9
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    
    
        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 =  | 
| 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: ' | 
| 91 | 
            -
                print ' password: ' | 
| 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: ' | 
| 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 '.' | 
| 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 | 
            -
               | 
| 282 | 
            -
             | 
| 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?( | 
| 309 | 
            -
             | 
| 310 | 
            -
             | 
| 311 | 
            -
             | 
| 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 ' | 
| 346 | 
            -
              task :current =>  | 
| 347 | 
            -
                 | 
| 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  | 
| 364 | 
            -
                 | 
| 365 | 
            -
             | 
| 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
         | 
    
        data/assets/rakelib/ruboto.rake
    CHANGED
    
    | @@ -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 | 
            -
             | 
| 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  | 
| 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 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                 | 
| 26 | 
            -
               | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 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 | 
| 39 | 
            -
            BUNDLE_PATH | 
| 40 | 
            -
            MANIFEST_FILE | 
| 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 | 
| 44 | 
            -
            GEM_LOCK_FILE | 
| 45 | 
            -
            RELEASE_APK_FILE | 
| 46 | 
            -
            APK_FILE | 
| 47 | 
            -
            TEST_APK_FILE | 
| 48 | 
            -
            JRUBY_JARS | 
| 49 | 
            -
            RESOURCE_FILES | 
| 50 | 
            -
            JAVA_SOURCE_FILES | 
| 51 | 
            -
            RUBY_SOURCE_FILES | 
| 52 | 
            -
            APK_DEPENDENCIES | 
| 53 | 
            -
            KEYSTORE_FILE | 
| 54 | 
            -
            KEYSTORE_ALIAS | 
| 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  | 
| 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  | 
| 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  | 
| 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  | 
| 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=').*?(')/){ | 
| 170 | 
            -
              manifest.sub!(/(android:targetSdkVersion=').*?(')/){ | 
| 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 =>  | 
| 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 | 
| 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 | 
            -
               | 
| 225 | 
            -
               | 
| 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}/ | 
| 228 | 
            -
              raise  | 
| 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[ | 
| 310 | 
            +
                Dir['*/lib/**/*'].each do |f|
         | 
| 261 311 | 
             
                  next if File.directory? f
         | 
| 262 | 
            -
                  raise  | 
| 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 | 
            -
               | 
| 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 | 
            -
               | 
| 362 | 
            -
              result
         | 
| 425 | 
            +
              path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
         | 
| 363 426 | 
             
            end
         | 
| 364 427 |  | 
| 365 | 
            -
             | 
| 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 | 
            -
               | 
| 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+) | 
| 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) ||  | 
| 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+) | 
| 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) ||  | 
| 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 | 
            -
               | 
| 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 | 
            -
               | 
| 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 =  | 
| 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  | 
| 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 =  | 
| 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  | 
| 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[ | 
| 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 | 
            -
               | 
| 593 | 
            +
              output !~ /Operation not permitted/
         | 
| 489 594 | 
             
            end
         |