Skip to content
This repository
Browse code

* Updated to Ruboto 0.7.0.dev

  • Loading branch information...
commit 6aa646e982dcf808c6671ac0dbb916311d0398d1 1 parent b0f26cd
Uwe Kubosch authored July 03, 2012
38  AndroidManifest.xml
... ...
@@ -1,9 +1,7 @@
1 1
 <?xml version='1.0' encoding='UTF-8'?> 
2  
-<manifest xmlns:android='http://schemas.android.com/apk/res/android' android:versionName='@string/version_name' package='org.ruboto.irb' 
3  
-      android:versionCode='12'  android:installLocation='preferExternal'>
4  
-    <application android:hardwareAccelerated='true' android:label='@string/app_name' android:icon='@drawable/icon' android:largeHeap='true'>
5  
-        <activity android:name='IRB' android:label='@string/app_name' android:windowSoftInputMode='adjustResize' 
6  
-              android:configChanges='orientation|screenSize' android:alwaysRetainTaskState="true">
  2
+<manifest android:versionCode='12' xmlns:android='http://schemas.android.com/apk/res/android' package='org.ruboto.irb' android:versionName='@string/version_name' android:installLocation='preferExternal'>
  3
+    <application android:hardwareAccelerated='true' android:largeHeap='true' android:icon='@drawable/icon' android:label='@string/app_name'>
  4
+        <activity android:name='IRB' android:alwaysRetainTaskState='true' android:windowSoftInputMode='adjustResize' android:configChanges='orientation|screenSize' android:label='@string/app_name'>
7 5
             <intent-filter>
8 6
                 <action android:name='android.intent.action.MAIN'/>
9 7
                 <category android:name='android.intent.category.LAUNCHER'/>
@@ -29,23 +27,23 @@
29 27
                 <category android:name='android.intent.category.DEFAULT'/>
30 28
             </intent-filter>
31 29
         </activity>
32  
-        <activity android:name='org.ruboto.RubotoActivity' android:configChanges='orientation|screenSize' android:alwaysRetainTaskState="true"/>
33  
-        <activity android:name='org.ruboto.RubotoDialog' android:theme='@android:style/Theme.Dialog' android:configChanges='orientation|screenSize'/>
  30
+        <activity android:name='org.ruboto.RubotoActivity' android:alwaysRetainTaskState='true' android:configChanges='orientation|screenSize'/>
  31
+        <activity android:theme='@android:style/Theme.Dialog' android:name='org.ruboto.RubotoDialog' android:configChanges='orientation|screenSize'/>
34 32
         <activity android:name='org.ruboto.RubotoPreferenceActivity'/>
35 33
         <service android:name='org.ruboto.RubotoService' android:exported='false'/>
36 34
     </application>
37  
-    <uses-sdk android:minSdkVersion='5' android:targetSdkVersion='13'/>
38  
-    <supports-screens android:smallScreens='true' android:normalScreens='true' android:largeScreens='true' android:xlargeScreens='true' android:anyDensity='true'/>
39  
-    <uses-feature android:required='false' android:name='android.hardware.telephony'/>
40  
-    <uses-feature android:required='false' android:name='android.hardware.touchscreen'/>
41  
-    <uses-feature android:required='false' android:name='android.hardware.location'/>
42  
-    <uses-feature android:required='false' android:name='android.hardware.location.gps'/>
43  
-    <uses-feature android:required='false' android:name='android.hardware.location.network'/>
44  
-    <uses-feature android:required='false' android:name='android.hardware.wifi'/>
45  
-    <uses-feature android:required='false' android:name='android.hardware.microphone'/>
46  
-    <uses-feature android:required='false' android:name='android.hardware.camera'/>
47  
-    <uses-feature android:required='false' android:name='android.hardware.camera.autofocus'/>
48  
-    <uses-feature android:required='false' android:name='android.hardware.bluetooth'/>
  35
+    <uses-sdk android:minSdkVersion='7' android:targetSdkVersion='13'/>
  36
+    <supports-screens android:normalScreens='true' android:largeScreens='true' android:xlargeScreens='true' android:anyDensity='true' android:smallScreens='true'/>
  37
+    <uses-feature android:name='android.hardware.telephony' android:required='false'/>
  38
+    <uses-feature android:name='android.hardware.touchscreen' android:required='false'/>
  39
+    <uses-feature android:name='android.hardware.location' android:required='false'/>
  40
+    <uses-feature android:name='android.hardware.location.gps' android:required='false'/>
  41
+    <uses-feature android:name='android.hardware.location.network' android:required='false'/>
  42
+    <uses-feature android:name='android.hardware.wifi' android:required='false'/>
  43
+    <uses-feature android:name='android.hardware.microphone' android:required='false'/>
  44
+    <uses-feature android:name='android.hardware.camera' android:required='false'/>
  45
+    <uses-feature android:name='android.hardware.camera.autofocus' android:required='false'/>
  46
+    <uses-feature android:name='android.hardware.bluetooth' android:required='false'/>
49 47
     <uses-permission android:name='android.permission.WRITE_EXTERNAL_STORAGE'/>
50 48
     <uses-permission android:name='com.android.launcher.permission.INSTALL_SHORTCUT'/>
51 49
     <uses-permission android:name='android.permission.INTERNET'/>
@@ -64,4 +62,4 @@
64 62
     <uses-permission android:name='android.permission.RECORD_AUDIO'/>
65 63
     <uses-permission android:name='android.permission.CAMERA'/>
66 64
     <uses-permission android:name='android.permission.BLUETOOTH'/>
67  
-</manifest>
  65
+</manifest>
409  Rakefile
... ...
@@ -1,407 +1,2 @@
1  
-if `ant -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.to_i == 1 && $2.to_i < 8)
2  
-  puts "ANT version 1.8.0 or later required.  Version found: #{$1}.#{$2}.#{$3}"
3  
-  exit 1
4  
-end
5  
-
6  
-require 'time'
7  
-
8  
-def manifest() @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
9  
-def package() manifest.root.attribute('package') end
10  
-def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
11  
-def scripts_path() @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
12  
-def app_files_path() @app_files_path ||= "/data/data/#{package}/files" end
13  
-
14  
-require 'rake/clean'
15  
-require 'rexml/document'
16  
-
17  
-PROJECT_DIR        = Dir.getwd
18  
-UPDATE_MARKER_FILE = File.expand_path(File.join('bin', 'LAST_UPDATE'), File.dirname(__FILE__))
19  
-BUNDLE_JAR         = File.expand_path 'libs/bundle.jar'
20  
-BUNDLE_PATH        = File.expand_path 'bin/bundle'
21  
-MANIFEST_FILE      = File.expand_path 'AndroidManifest.xml'
22  
-RUBOTO_CONFIG_FILE = File.expand_path 'ruboto.yml'
23  
-GEM_FILE           = File.expand_path('Gemfile.apk')
24  
-GEM_LOCK_FILE      = File.expand_path('Gemfile.apk.lock')
25  
-RELEASE_APK_FILE   = File.expand_path "bin/#{build_project_name}-release.apk"
26  
-APK_FILE           = File.expand_path "bin/#{build_project_name}-debug.apk"
27  
-TEST_APK_FILE      = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
28  
-JRUBY_JARS         = Dir[File.expand_path 'libs/jruby-*.jar']
29  
-RESOURCE_FILES     = Dir[File.expand_path 'res/**/*']
30  
-JAVA_SOURCE_FILES  = Dir[File.expand_path 'src/**/*.java']
31  
-RUBY_SOURCE_FILES  = Dir[File.expand_path 'src/**/*.rb']
32  
-APK_DEPENDENCIES   = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
33  
-KEYSTORE_FILE      = (key_store = File.readlines('ant.properties').grep(/^key.store=/).first) ? key_store.chomp.sub(/^key.store=/, '') : "#{build_project_name}.keystore"
34  
-KEYSTORE_ALIAS     = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
35  
-
36  
-CLEAN.include('bin')
37  
-
38  
-task :default => :debug
39  
-
40  
-file JRUBY_JARS => RUBOTO_CONFIG_FILE do
41  
-  next unless File.exists? RUBOTO_CONFIG_FILE
42  
-  jruby_jars_mtime = JRUBY_JARS.map { |f| File.mtime(f) }.min
43  
-  ruboto_yml_mtime = File.mtime(RUBOTO_CONFIG_FILE)
44  
-  next if jruby_jars_mtime > ruboto_yml_mtime
45  
-  puts '*' * 80
46  
-  if JRUBY_JARS.empty?
47  
-    puts '  The JRuby jars are missing.'
48  
-  else
49  
-    puts "  The JRuby jars need reconfiguring after changes to #{RUBOTO_CONFIG_FILE}"
50  
-    puts "  #{RUBOTO_CONFIG_FILE}: #{ruboto_yml_mtime}"
51  
-    puts "  #{JRUBY_JARS.join(', ')}: #{jruby_jars_mtime}"
52  
-  end
53  
-  puts '  Run "ruboto update jruby" to regenerate the JRuby jars'
54  
-  puts '*' * 80
55  
-end
56  
-
57  
-desc 'build debug package'
58  
-task :debug => APK_FILE
59  
-
60  
-namespace :debug do
61  
-  desc 'build debug package if compiled files have changed'
62  
-  task :quick => [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES do |t|
63  
-    build_apk(t, false)
64  
-  end
65  
-end
66  
-
67  
-desc "build package and install it on the emulator or device"
68  
-task :install => APK_FILE do
69  
-  install_apk
70  
-end
71  
-
72  
-namespace :install do
73  
-  desc 'uninstall, build, and install the application'
74  
-  task :clean => [:uninstall, APK_FILE, :install]
75  
-
76  
-  desc 'Install the application, but only if compiled files are changed.'
77  
-  task :quick => 'debug:quick' do
78  
-    install_apk
79  
-  end
80  
-end
81  
-
82  
-desc 'Build APK for release'
83  
-task :release => RELEASE_APK_FILE
84  
-
85  
-file RELEASE_APK_FILE => [KEYSTORE_FILE] + APK_DEPENDENCIES do |t|
86  
-  build_apk(t, true)
87  
-end
88  
-
89  
-desc 'Create a keystore for signing the release APK'
90  
-file KEYSTORE_FILE do
91  
-  unless File.read('ant.properties') =~ /^key.store=/
92  
-    File.open('ant.properties', 'a'){|f| f << "\nkey.store=#{KEYSTORE_FILE}\n"}
93  
-  end
94  
-  unless File.read('ant.properties') =~ /^key.alias=/
95  
-    File.open('ant.properties', 'a'){|f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n"}
96  
-  end
97  
-  sh "keytool -genkey -v -keystore #{KEYSTORE_FILE} -alias #{KEYSTORE_ALIAS} -keyalg RSA -keysize 2048 -validity 10000"
98  
-end
99  
-
100  
-desc 'Tag this working copy with the current version'
101  
-task :tag => :release do
102  
-  unless `git branch` =~ /^\* master$/
103  
-    puts "You must be on the master branch to release!"
104  
-    exit!
105  
-  end
106  
-  # sh "git commit --allow-empty -a -m 'Release #{version}'"
107  
-  output = `git status --porcelain`
108  
-  raise "Workspace not clean!\n#{output}" unless output.empty?
109  
-  sh "git tag #{version}"
110  
-  sh "git push origin master --tags"
111  
-end
112  
-
113  
-task :sign => :release do
114  
-  sh "jarsigner -keystore #{ENV['RUBOTO_KEYSTORE']} -signedjar bin/#{build_project_name}.apk bin/#{build_project_name}-unsigned.apk #{ENV['RUBOTO_KEY_ALIAS']}"
115  
-end
116  
-
117  
-task :align => :sign do
118  
-  sh "zipalign 4 bin/#{build_project_name}.apk #{build_project_name}.apk"
119  
-end
120  
-
121  
-task :publish => :align do
122  
-  puts "#{build_project_name}.apk is ready for the market!"
123  
-end
124  
-
125  
-desc 'Start the emulator with larger disk'
126  
-task :emulator do
127  
-  sh 'emulator -partition-size 1024 -avd Android_3.0'
128  
-end
129  
-
130  
-task :start do
131  
-  start_app
132  
-end
133  
-
134  
-task :stop do
135  
-  raise "Unable to stop app.  Only available on emulator." unless stop_app
136  
-end
137  
-
138  
-desc 'Restart the application'
139  
-task :restart => [:stop, :start]
140  
-
141  
-task :uninstall do
142  
-  uninstall_apk
143  
-end
144  
-
145  
-file MANIFEST_FILE
146  
-file RUBOTO_CONFIG_FILE
147  
-
148  
-file APK_FILE => APK_DEPENDENCIES do |t|
149  
-  build_apk(t, false)
150  
-end
151  
-
152  
-desc 'Copy scripts to emulator or device'
153  
-task :update_scripts => ['install:quick'] do
154  
-  update_scripts
155  
-end
156  
-
157  
-namespace :update_scripts do
158  
-  desc 'Copy scripts to emulator and restart the app'
159  
-  task :restart => APK_DEPENDENCIES do |t|
160  
-    if build_apk(t, false) || !stop_app
161  
-      install_apk
162  
-    else
163  
-      update_scripts
164  
-    end
165  
-    start_app
166  
-  end
167  
-end
168  
-
169  
-task :test => :uninstall do
170  
-  Dir.chdir('test') do
171  
-    puts 'Running tests'
172  
-    sh "adb uninstall #{package}.tests"
173  
-    sh "ant instrument install test"
174  
-  end
175  
-end
176  
-
177  
-namespace :test do
178  
-  task :quick => :update_scripts do
179  
-    Dir.chdir('test') do
180  
-      puts 'Running quick tests'
181  
-      sh 'ant instrument'
182  
-      sh 'ant installi'
183  
-      sh "ant run-tests-quick"
184  
-    end
185  
-  end
186  
-end
187  
-
188  
-file GEM_FILE
189  
-file GEM_LOCK_FILE
190  
-
191  
-desc 'Generate bundle jar from Gemfile'
192  
-task :bundle => BUNDLE_JAR
193  
-
194  
-file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
195  
-  next unless File.exists? GEM_FILE
196  
-  puts "Generating #{BUNDLE_JAR}"
197  
-
198  
-  FileUtils.mkdir_p BUNDLE_PATH
199  
-  sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH}"
200  
-  gem_path = Dir["#{BUNDLE_PATH}/*ruby/1.8/gems"][0]
201  
-
202  
-  if package != 'org.ruboto.core' && JRUBY_JARS.none? { |f| File.exists? f }
203  
-    Dir.chdir gem_path do
204  
-      Dir['activerecord-jdbc-adapter-*'].each do |g|
205  
-        puts "Removing #{g} gem since it is included in the RubotoCore platform apk."
206  
-        FileUtils.rm_rf g
207  
-      end
208  
-    end
209  
-  end
210  
-
211  
-  # Remove duplicate files
212  
-  Dir.chdir gem_path do
213  
-    scanned_files = []
214  
-    source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
215  
-    Dir["*/lib/**/*"].each do |f|
216  
-      next if File.directory? f
217  
-      raise "Malformed file name" unless f =~ %r{^(.*?)/lib/(.*)$}
218  
-      gem_name, lib_file = $1, $2
219  
-      if existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} }
220  
-        puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
221  
-        FileUtils.rm existing_file
222  
-        scanned_files.delete existing_file
223  
-      elsif source_files.include? lib_file
224  
-        puts "Removing duplicate file #{lib_file} in gem #{gem_name}"
225  
-        puts "Already present in project source src/#{lib_file}"
226  
-        FileUtils.rm f
227  
-        next
228  
-      end
229  
-      scanned_files << f
230  
-    end
231  
-  end
232  
-
233  
-  # Expand JARs
234  
-  Dir.chdir gem_path do
235  
-    Dir['*'].each do |gem_lib|
236  
-      Dir.chdir "#{gem_lib}/lib" do
237  
-        Dir['**/*.jar'].each do |jar|
238  
-          unless jar =~ /sqlite-jdbc/
239  
-            puts "Expanding #{gem_lib} #{jar} into #{BUNDLE_JAR}"
240  
-            `jar xf #{jar}`
241  
-          end
242  
-          if jar == 'arjdbc/jdbc/adapter_java.jar'
243  
-            jar_load_code = <<-END_CODE
244  
-require 'jruby'
245  
-Java::arjdbc.jdbc.AdapterJavaService.new.basicLoad(JRuby.runtime)
246  
-            END_CODE
247  
-          else
248  
-            jar_load_code = ''
249  
-          end
250  
-          puts "Writing dummy JAR file #{jar + '.rb'}"
251  
-          File.open(jar + '.rb', 'w') { |f| f << jar_load_code }
252  
-          if jar.end_with?('.jar')
253  
-            puts "Writing dummy JAR file #{jar.sub(/.jar$/, '.rb')}"
254  
-            File.open(jar.sub(/.jar$/, '.rb'), 'w') { |f| f << jar_load_code }
255  
-          end
256  
-          FileUtils.rm_f(jar)
257  
-        end
258  
-      end
259  
-    end
260  
-  end
261  
-
262  
-
263  
-  FileUtils.rm_f BUNDLE_JAR
264  
-  Dir["#{gem_path}/*"].each_with_index do |gem_dir, i|
265  
-    `jar #{i == 0 ? 'c' : 'u'}f #{BUNDLE_JAR} -C #{gem_dir}/lib .`
266  
-  end
267  
-  FileUtils.rm_rf BUNDLE_PATH
268  
-end
269  
-
270  
-# Methods
271  
-
272  
-def mark_update(time = Time.now)
273  
-  FileUtils.mkdir_p File.dirname(UPDATE_MARKER_FILE)
274  
-  File.open(UPDATE_MARKER_FILE, 'w') { |f| f << time.iso8601 }
275  
-end
276  
-
277  
-def clear_update
278  
-  mark_update File.ctime APK_FILE
279  
-  if device_path_exists?(scripts_path)
280  
-    sh "adb shell rm -r #{scripts_path}"
281  
-    puts "Deleted scripts directory #{scripts_path}"
282  
-  end
283  
-end
284  
-
285  
-def strings(name)
286  
-  @strings ||= REXML::Document.new(File.read('res/values/strings.xml'))
287  
-  value = @strings.elements["//string[@name='#{name.to_s}']"] or raise "string '#{name}' not found in strings.xml"
288  
-  value.text
289  
-end
290  
-
291  
-def version()
292  
-  strings :version_name
293  
-end
294  
-
295  
-def app_name()
296  
-  strings :app_name
297  
-end
298  
-
299  
-def main_activity()
300  
-  manifest.root.elements['application'].elements["activity[@android:label='@string/app_name']"].attribute('android:name')
301  
-end
302  
-
303  
-def device_path_exists?(path)
304  
-  path_output =`adb shell ls #{path}`
305  
-  result = path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
306  
-  result
307  
-end
308  
-
309  
-def package_installed? test = false
310  
-  package_name = "#{package}#{'.tests' if test}"
311  
-  ['', '-0', '-1', '-2'].each do |i|
312  
-    p = "/data/app/#{package_name}#{i}.apk"
313  
-    o = `adb shell ls -l #{p}`.chomp
314  
-    if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(p)}$/
315  
-      apk_file = test ? TEST_APK_FILE : APK_FILE
316  
-      if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
317  
-        return true
318  
-      else
319  
-        return false
320  
-      end
321  
-    end
322  
-  end
323  
-  return nil
324  
-end
325  
-
326  
-private
327  
-
328  
-def replace_faulty_code(faulty_file, faulty_code)
329  
-  explicit_requires = Dir["#{faulty_file.chomp('.rb')}/*.rb"].sort.map { |f| File.basename(f) }.map do |filename|
330  
-    "require 'active_model/validations/#{filename}'"
331  
-  end.join("\n")
332  
-
333  
-  old_code = File.read(faulty_file)
334  
-  new_code = old_code.gsub faulty_code, explicit_requires
335  
-  if new_code != old_code
336  
-    puts "Replaced directory listing code in file #{faulty_file} with explicit requires."
337  
-    File.open(faulty_file, 'w') { |f| f << new_code }
338  
-  else
339  
-    puts "Could not find expected faulty code\n\n#{faulty_code}\n\nin file #{faulty_file}\n\n#{old_code}\n\n"
340  
-  end
341  
-end
342  
-
343  
-def build_apk(t, release)
344  
-  apk_file = release ? RELEASE_APK_FILE : APK_FILE
345  
-  if File.exist?(apk_file)
346  
-    changed_prereqs = t.prerequisites.select do |p|
347  
-      File.file?(p) && !Dir[p].empty? && Dir[p].map { |f| File.mtime(f) }.max > File.mtime(APK_FILE)
348  
-    end
349  
-    return false if changed_prereqs.empty?
350  
-    changed_prereqs.each { |f| puts "#{f} changed." }
351  
-    puts "Forcing rebuild of #{apk_file}."
352  
-  end
353  
-  if release
354  
-    sh 'ant release'
355  
-  else
356  
-    sh 'ant debug'
357  
-  end
358  
-  return true
359  
-end
360  
-
361  
-def install_apk
362  
-  case package_installed?
363  
-  when true
364  
-    puts "Package already installed."
365  
-    return
366  
-  when false
367  
-    puts "Package installed, but of wrong size."
368  
-  end
369  
-  sh 'ant installd'
370  
-  clear_update
371  
-end
372  
-
373  
-def uninstall_apk
374  
-  return if package_installed?.nil?
375  
-  puts "Uninstalling package #{package}"
376  
-  system "adb uninstall #{package}"
377  
-  if $? != 0 && package_installed?
378  
-    puts "Uninstall failed exit code #{$?}"
379  
-    exit $?
380  
-  end
381  
-end
382  
-
383  
-def update_scripts
384  
-  `adb shell mkdir -p #{scripts_path}` if !device_path_exists?(scripts_path)
385  
-  puts "Pushing files to apk public file area."
386  
-  last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
387  
-  # TODO(uwe): Use `adb sync src` instead?
388  
-  Dir.chdir('src') do
389  
-    Dir["**/*.rb"].each do |script_file|
390  
-      next if File.directory? script_file
391  
-      next if File.mtime(script_file) < last_update
392  
-      next if script_file =~ /~$/
393  
-      print "#{script_file}: "; $stdout.flush
394  
-      `adb push #{script_file} #{scripts_path}/#{script_file}`
395  
-    end
396  
-  end
397  
-  mark_update
398  
-end
399  
-
400  
-def start_app
401  
-  `adb shell am start -a android.intent.action.MAIN -n #{package}/.#{main_activity}`
402  
-end
403  
-
404  
-def stop_app
405  
-  output = `adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
406  
-  return output !~ /Operation not permitted/
407  
-end
  1
+# Write your own rake tasks here.
  2
+# You can find the Ruboto rake tasks in rakelib/ruboto.rake
41  build.xml
@@ -4,7 +4,7 @@
4 4
     <!-- The local.properties file is created and updated by the 'android' tool.
5 5
          It contains the path to the SDK. It should *NOT* be checked into
6 6
          Version Control Systems. -->
7  
-    <loadproperties srcFile="local.properties" />
  7
+    <property file="local.properties" />
8 8
 
9 9
     <!-- The ant.properties file can be created by you. It is only edited by the
10 10
          'android' tool to add properties to it.
@@ -28,6 +28,15 @@
28 28
          -->
29 29
     <property file="ant.properties" />
30 30
 
  31
+    <!-- if sdk.dir was not set from one of the property file, then
  32
+         get it from the ANDROID_HOME env var.
  33
+         This must be done before we load project.properties since
  34
+         the proguard config can use sdk.dir -->
  35
+    <property environment="env" />
  36
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
  37
+        <isset property="env.ANDROID_HOME" />
  38
+    </condition>
  39
+
31 40
     <!-- The project.properties file is created and updated by the 'android'
32 41
          tool, as well as ADT.
33 42
 
@@ -41,25 +50,23 @@
41 50
 
42 51
     <!-- quick check on sdk.dir -->
43 52
     <fail
44  
-            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
  53
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
45 54
             unless="sdk.dir"
46 55
     />
47 56
 
48  
-
49  
-<!-- extension targets. Uncomment the ones where you want to do custom work
50  
-     in between standard targets -->
51  
-<!--
52  
-    <target name="-pre-build">
53  
-    </target>
54  
-    <target name="-pre-compile">
55  
-    </target>
56  
-
57  
-    /* This is typically used for code obfuscation.
58  
-       Compiled code location: ${out.classes.absolute.dir}
59  
-       If this is not done in place, override ${out.dex.input.absolute.dir} */
60  
-    <target name="-post-compile">
61  
-    </target>
62  
--->
  57
+    <!--
  58
+        Import per project custom build rules if present at the root of the project.
  59
+        This is the place to put custom intermediary targets such as:
  60
+            -pre-build
  61
+            -pre-compile
  62
+            -post-compile (This is typically used for code obfuscation.
  63
+                           Compiled code location: ${out.classes.absolute.dir}
  64
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
  65
+            -post-package
  66
+            -post-build
  67
+            -pre-clean
  68
+    -->
  69
+    <import file="custom_rules.xml" optional="true" />
63 70
 
64 71
     <!-- Import the actual build file.
65 72
 
20  proguard-project.txt
... ...
@@ -0,0 +1,20 @@
  1
+# To enable ProGuard in your project, edit project.properties
  2
+# to define the proguard.config property as described in that file.
  3
+#
  4
+# Add project specific ProGuard rules here.
  5
+# By default, the flags in this file are appended to flags specified
  6
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
  7
+# You can edit the include path and order by changing the ProGuard
  8
+# include property in project.properties.
  9
+#
  10
+# For more details, see
  11
+#   http://developer.android.com/guide/developing/tools/proguard.html
  12
+
  13
+# Add any project specific keep options here:
  14
+
  15
+# If your project uses WebView with JS, uncomment the following
  16
+# and specify the fully qualified class name to the JavaScript interface
  17
+# class:
  18
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  19
+#   public *;
  20
+#}
448  rakelib/ruboto.rake
... ...
@@ -0,0 +1,448 @@
  1
+if `ant -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.to_i == 1 && $2.to_i < 8)
  2
+  puts "ANT version 1.8.0 or later required.  Version found: #{$1}.#{$2}.#{$3}"
  3
+  exit 1
  4
+end
  5
+
  6
+require 'time'
  7
+
  8
+def manifest() @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
  9
+def package() manifest.root.attribute('package') end
  10
+def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
  11
+def scripts_path() @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
  12
+def app_files_path() @app_files_path ||= "/data/data/#{package}/files" end
  13
+
  14
+require 'rake/clean'
  15
+require 'rexml/document'
  16
+
  17
+PROJECT_DIR        = File.expand_path('..', File.dirname(__FILE__))
  18
+UPDATE_MARKER_FILE = File.join(PROJECT_DIR, 'bin', 'LAST_UPDATE')
  19
+BUNDLE_JAR         = File.expand_path 'libs/bundle.jar'
  20
+BUNDLE_PATH        = File.expand_path 'bin/bundle'
  21
+MANIFEST_FILE      = File.expand_path 'AndroidManifest.xml'
  22
+PROJECT_PROPS_FILE = File.expand_path 'project.properties'
  23
+RUBOTO_CONFIG_FILE = File.expand_path 'ruboto.yml'
  24
+GEM_FILE           = File.expand_path('Gemfile.apk')
  25
+GEM_LOCK_FILE      = File.expand_path('Gemfile.apk.lock')
  26
+RELEASE_APK_FILE   = File.expand_path "bin/#{build_project_name}-release.apk"
  27
+APK_FILE           = File.expand_path "bin/#{build_project_name}-debug.apk"
  28
+TEST_APK_FILE      = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
  29
+JRUBY_JARS         = Dir[File.expand_path 'libs/jruby-*.jar']
  30
+RESOURCE_FILES     = Dir[File.expand_path 'res/**/*']
  31
+JAVA_SOURCE_FILES  = Dir[File.expand_path 'src/**/*.java']
  32
+RUBY_SOURCE_FILES  = Dir[File.expand_path 'src/**/*.rb']
  33
+APK_DEPENDENCIES   = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
  34
+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"
  35
+KEYSTORE_ALIAS     = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
  36
+
  37
+CLEAN.include('bin')
  38
+
  39
+task :default => :debug
  40
+
  41
+file JRUBY_JARS => RUBOTO_CONFIG_FILE do
  42
+  next unless File.exists? RUBOTO_CONFIG_FILE
  43
+  jruby_jars_mtime = JRUBY_JARS.map { |f| File.mtime(f) }.min
  44
+  ruboto_yml_mtime = File.mtime(RUBOTO_CONFIG_FILE)
  45
+  next if jruby_jars_mtime > ruboto_yml_mtime
  46
+  puts '*' * 80
  47
+  if JRUBY_JARS.empty?
  48
+    puts '  The JRuby jars are missing.'
  49
+  else
  50
+    puts "  The JRuby jars need reconfiguring after changes to #{RUBOTO_CONFIG_FILE}"
  51
+    puts "  #{RUBOTO_CONFIG_FILE}: #{ruboto_yml_mtime}"
  52
+    puts "  #{JRUBY_JARS.join(', ')}: #{jruby_jars_mtime}"
  53
+  end
  54
+  puts '  Run "ruboto update jruby" to regenerate the JRuby jars'
  55
+  puts '*' * 80
  56
+end
  57
+
  58
+desc 'build debug package'
  59
+task :debug => APK_FILE
  60
+
  61
+namespace :debug do
  62
+  desc 'build debug package if compiled files have changed'
  63
+  task :quick => [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES do |t|
  64
+    build_apk(t, false)
  65
+  end
  66
+end
  67
+
  68
+desc "build package and install it on the emulator or device"
  69
+task :install => APK_FILE do
  70
+  install_apk
  71
+end
  72
+
  73
+namespace :install do
  74
+  desc 'uninstall, build, and install the application'
  75
+  task :clean => [:uninstall, APK_FILE, :install]
  76
+
  77
+  desc 'Install the application, but only if compiled files are changed.'
  78
+  task :quick => 'debug:quick' do
  79
+    install_apk
  80
+  end
  81
+end
  82
+
  83
+desc 'Build APK for release'
  84
+task :release => RELEASE_APK_FILE
  85
+
  86
+file RELEASE_APK_FILE => [KEYSTORE_FILE] + APK_DEPENDENCIES do |t|
  87
+  build_apk(t, true)
  88
+end
  89
+
  90
+desc 'Create a keystore for signing the release APK'
  91
+file KEYSTORE_FILE do
  92
+  unless File.read('ant.properties') =~ /^key.store=/
  93
+    File.open('ant.properties', 'a'){|f| f << "\nkey.store=#{KEYSTORE_FILE}\n"}
  94
+  end
  95
+  unless File.read('ant.properties') =~ /^key.alias=/
  96
+    File.open('ant.properties', 'a'){|f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n"}
  97
+  end
  98
+  sh "keytool -genkey -v -keystore #{KEYSTORE_FILE} -alias #{KEYSTORE_ALIAS} -keyalg RSA -keysize 2048 -validity 10000"
  99
+end
  100
+
  101
+desc 'Tag this working copy with the current version'
  102
+task :tag => :release do
  103
+  unless `git branch` =~ /^\* master$/
  104
+    puts "You must be on the master branch to release!"
  105
+    exit!
  106
+  end
  107
+  # sh "git commit --allow-empty -a -m 'Release #{version}'"
  108
+  output = `git status --porcelain`
  109
+  raise "Workspace not clean!\n#{output}" unless output.empty?
  110
+  sh "git tag #{version}"
  111
+  sh "git push origin master --tags"
  112
+end
  113
+
  114
+task :sign => :release do
  115
+  sh "jarsigner -keystore #{ENV['RUBOTO_KEYSTORE']} -signedjar bin/#{build_project_name}.apk bin/#{build_project_name}-unsigned.apk #{ENV['RUBOTO_KEY_ALIAS']}"
  116
+end
  117
+
  118
+task :align => :sign do
  119
+  sh "zipalign 4 bin/#{build_project_name}.apk #{build_project_name}.apk"
  120
+end
  121
+
  122
+task :publish => :align do
  123
+  puts "#{build_project_name}.apk is ready for the market!"
  124
+end
  125
+
  126
+desc 'Start the emulator with larger disk'
  127
+task :emulator do
  128
+  sh 'emulator -partition-size 1024 -avd Android_3.0'
  129
+end
  130
+
  131
+task :start do
  132
+  start_app
  133
+end
  134
+
  135
+task :stop do
  136
+  raise "Unable to stop app.  Only available on emulator." unless stop_app
  137
+end
  138
+
  139
+desc 'Restart the application'
  140
+task :restart => [:stop, :start]
  141
+
  142
+task :uninstall do
  143
+  uninstall_apk
  144
+end
  145
+
  146
+file PROJECT_PROPS_FILE
  147
+file MANIFEST_FILE => PROJECT_PROPS_FILE do
  148
+  sdk_level = File.read(PROJECT_PROPS_FILE).scan(/(?:target=android-)(\d+)/)[0][0].to_i
  149
+  old_manifest = File.read(MANIFEST_FILE)
  150
+  manifest = old_manifest.dup
  151
+  manifest.sub!(/(android:minSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
  152
+  manifest.sub!(/(android:targetSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
  153
+  File.open(MANIFEST_FILE, 'w'){|f| f << manifest} if manifest != old_manifest
  154
+end
  155
+
  156
+file RUBOTO_CONFIG_FILE
  157
+
  158
+file APK_FILE => APK_DEPENDENCIES do |t|
  159
+  build_apk(t, false)
  160
+end
  161
+
  162
+desc 'Copy scripts to emulator or device'
  163
+task :update_scripts => ['install:quick'] do
  164
+  update_scripts
  165
+end
  166
+
  167
+namespace :update_scripts do
  168
+  desc 'Copy scripts to emulator and restart the app'
  169
+  task :restart => APK_DEPENDENCIES do |t|
  170
+    if build_apk(t, false) || !stop_app
  171
+      install_apk
  172
+    else
  173
+      update_scripts
  174
+    end
  175
+    start_app
  176
+  end
  177
+end
  178
+
  179
+task :test => :uninstall do
  180
+  Dir.chdir('test') do
  181
+    puts 'Running tests'
  182
+    sh "adb uninstall #{package}.tests"
  183
+    sh "ant instrument install test"
  184
+  end
  185
+end
  186
+
  187
+namespace :test do
  188
+  task :quick => :update_scripts do
  189
+    Dir.chdir('test') do
  190
+      puts 'Running quick tests'
  191
+      sh 'ant instrument'
  192
+      sh 'ant installi'
  193
+      sh "ant run-tests-quick"
  194
+    end
  195
+  end
  196
+end
  197
+
  198
+file GEM_FILE
  199
+file GEM_LOCK_FILE
  200
+
  201
+desc 'Generate bundle jar from Gemfile'
  202
+task :bundle => BUNDLE_JAR
  203
+
  204
+file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
  205
+  next unless File.exists? GEM_FILE
  206
+  puts "Generating #{BUNDLE_JAR}"
  207
+
  208
+  FileUtils.mkdir_p BUNDLE_PATH
  209
+  sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH}"
  210
+  gem_path = Dir["#{BUNDLE_PATH}/*ruby/1.8/gems"][0]
  211
+
  212
+  if package != 'org.ruboto.core' && JRUBY_JARS.none? { |f| File.exists? f }
  213
+    Dir.chdir gem_path do
  214
+      Dir['{activerecord-jdbc-adapter, jruby-openssl}-*'].each do |g|
  215
+        puts "Removing #{g} gem since it is included in the RubotoCore platform apk."
  216
+        FileUtils.rm_rf g
  217
+      end
  218
+    end
  219
+  else
  220
+    Dir.chdir gem_path do
  221
+      Dir['jruby-openssl-*/lib'].each do |g|
  222
+        rel_dir = "#{g}/lib/ruby"
  223
+        unless File.exists? rel_dir
  224
+          puts "Relocating #{g} files to match standard load path."
  225
+          dirs = Dir["#{g}/*"]
  226
+          FileUtils.mkdir_p rel_dir
  227
+          dirs.each do |d|
  228
+            FileUtils.move d, rel_dir
  229
+          end
  230
+        end
  231
+      end
  232
+    end
  233
+  end
  234
+
  235
+  # Remove duplicate files
  236
+  Dir.chdir gem_path do
  237
+    scanned_files = []
  238
+    source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
  239
+    Dir["*/lib/**/*"].each do |f|
  240
+      next if File.directory? f
  241
+      raise "Malformed file name" unless f =~ %r{^(.*?)/lib/(.*)$}
  242
+      gem_name, lib_file = $1, $2
  243
+      if existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} }
  244
+        puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
  245
+        FileUtils.rm existing_file
  246
+        scanned_files.delete existing_file
  247
+      elsif source_files.include? lib_file
  248
+        puts "Removing duplicate file #{lib_file} in gem #{gem_name}"
  249
+        puts "Already present in project source src/#{lib_file}"
  250
+        FileUtils.rm f
  251
+        next
  252
+      end
  253
+      scanned_files << f
  254
+    end
  255
+  end
  256
+
  257
+  # Expand JARs
  258
+  Dir.chdir gem_path do
  259
+    Dir['*'].each do |gem_lib|
  260
+      Dir.chdir "#{gem_lib}/lib" do
  261
+        Dir['**/*.jar'].each do |jar|
  262
+          if jar == 'arjdbc/jdbc/adapter_java.jar'
  263
+            jar_load_code = <<-END_CODE
  264
+require 'jruby'
  265
+Java::arjdbc.jdbc.AdapterJavaService.new.basicLoad(JRuby.runtime)
  266
+            END_CODE
  267
+          elsif jar =~ /shared\/jopenssl.jar$/
  268
+            jar_load_code = <<-END_CODE
  269
+require 'jruby'
  270
+puts 'Starting JRuby OpenSSL Service'
  271
+public
  272
+Java::JopensslService.new.basicLoad(JRuby.runtime)
  273
+            END_CODE
  274
+          else
  275
+            jar_load_code = ''
  276
+          end
  277
+          unless jar =~ /sqlite-jdbc/
  278
+            puts "Expanding #{gem_lib} #{jar} into #{BUNDLE_JAR}"
  279
+            `jar xf #{jar}`
  280
+          end
  281
+          puts "Writing dummy JAR file #{jar + '.rb'}"
  282
+          File.open(jar + '.rb', 'w') { |f| f << jar_load_code }
  283
+          if jar.end_with?('.jar')
  284
+            puts "Writing dummy JAR file #{jar.sub(/.jar$/, '.rb')}"
  285
+            File.open(jar.sub(/.jar$/, '.rb'), 'w') { |f| f << jar_load_code }
  286
+          end
  287
+          FileUtils.rm_f(jar)
  288
+        end
  289
+      end
  290
+    end
  291
+  end
  292
+
  293
+
  294
+  FileUtils.rm_f BUNDLE_JAR
  295
+  Dir["#{gem_path}/*"].each_with_index do |gem_dir, i|
  296
+    `jar #{i == 0 ? 'c' : 'u'}f #{BUNDLE_JAR} -C #{gem_dir}/lib .`
  297
+  end
  298
+  FileUtils.rm_rf BUNDLE_PATH
  299
+end
  300
+
  301
+# Methods
  302
+
  303
+def mark_update(time = Time.now)
  304
+  FileUtils.mkdir_p File.dirname(UPDATE_MARKER_FILE)
  305
+  File.open(UPDATE_MARKER_FILE, 'w') { |f| f << time.iso8601 }
  306
+end
  307
+
  308
+def clear_update
  309
+  mark_update File.ctime APK_FILE
  310
+  if device_path_exists?(scripts_path)
  311
+    sh "adb shell rm -r #{scripts_path}"
  312
+    puts "Deleted scripts directory #{scripts_path}"
  313
+  end
  314
+end
  315
+
  316
+def strings(name)
  317
+  @strings ||= REXML::Document.new(File.read('res/values/strings.xml'))
  318
+  value = @strings.elements["//string[@name='#{name.to_s}']"] or raise "string '#{name}' not found in strings.xml"
  319
+  value.text
  320
+end
  321
+
  322
+def version()
  323
+  strings :version_name
  324
+end
  325
+
  326
+def app_name()
  327
+  strings :app_name
  328
+end
  329
+
  330
+def main_activity()
  331
+  manifest.root.elements['application'].elements["activity[@android:label='@string/app_name']"].attribute('android:name')
  332
+end
  333
+
  334
+def device_path_exists?(path)
  335
+  path_output =`adb shell ls #{path}`
  336
+  result = path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
  337
+  result
  338
+end
  339
+
  340
+def package_installed? test = false
  341
+  package_name = "#{package}#{'.tests' if test}"
  342
+  ['', '-0', '-1', '-2'].each do |i|
  343
+    path = "/data/app/#{package_name}#{i}.apk"
  344
+    o = `adb shell ls -l #{path}`.chomp
  345
+    if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(path)}$/
  346
+      apk_file = test ? TEST_APK_FILE : APK_FILE
  347
+      if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
  348
+        return true
  349
+      else
  350
+        return false
  351
+      end
  352
+    end
  353
+  end
  354
+  return nil
  355
+end
  356
+
  357
+def replace_faulty_code(faulty_file, faulty_code)
  358
+  explicit_requires = Dir["#{faulty_file.chomp('.rb')}/*.rb"].sort.map { |f| File.basename(f) }.map do |filename|
  359
+    "require 'active_model/validations/#{filename}'"
  360
+  end.join("\n")
  361
+
  362
+  old_code = File.read(faulty_file)
  363
+  new_code = old_code.gsub faulty_code, explicit_requires
  364
+  if new_code != old_code
  365
+    puts "Replaced directory listing code in file #{faulty_file} with explicit requires."
  366
+    File.open(faulty_file, 'w') { |f| f << new_code }
  367
+  else
  368
+    puts "Could not find expected faulty code\n\n#{faulty_code}\n\nin file #{faulty_file}\n\n#{old_code}\n\n"
  369
+  end
  370
+end
  371
+
  372
+def build_apk(t, release)
  373
+  apk_file = release ? RELEASE_APK_FILE : APK_FILE
  374
+  if File.exist?(apk_file)
  375
+    changed_prereqs = t.prerequisites.select do |p|
  376
+      File.file?(p) && !Dir[p].empty? && Dir[p].map { |f| File.mtime(f) }.max > File.mtime(APK_FILE)
  377
+    end
  378
+    return false if changed_prereqs.empty?
  379
+    changed_prereqs.each { |f| puts "#{f} changed." }
  380
+    puts "Forcing rebuild of #{apk_file}."
  381
+  end
  382
+  if release
  383
+    sh 'ant release'
  384
+  else
  385
+    sh 'ant debug'
  386
+  end
  387
+  return true
  388
+end
  389
+
  390
+def install_apk
  391
+  failure_pattern = /^Failure \[(.*)\]/
  392
+  success_pattern = /^Success/
  393
+  case package_installed?
  394
+  when true
  395
+    puts "Package #{package} already installed."
  396
+    return
  397
+  when false
  398
+    puts "Package #{package} already installed, but of different size.  Replacing package."
  399
+    output = `adb install -r #{APK_FILE} 2>&1`
  400
+    return if $? == 0 && output !~ failure_pattern && output =~ success_pattern
  401
+    case $1
  402
+    when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
  403
+      puts "Found package signed with different certificate.  Uninstalling it and retrying install."
  404
+    else
  405
+      puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
  406
+      puts "Uninstalling #{package} and retrying install."
  407
+    end
  408
+    uninstall_apk
  409
+  end
  410
+  output = `adb install #{APK_FILE} 2>&1`
  411
+  raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
  412
+  clear_update
  413
+end
  414
+
  415
+def uninstall_apk
  416
+  return if package_installed?.nil?
  417
+  puts "Uninstalling package #{package}"
  418
+  system "adb uninstall #{package}"
  419
+  if $? != 0 && package_installed?
  420
+    puts "Uninstall failed exit code #{$?}"
  421
+    exit $?
  422
+  end
  423
+end
  424
+
  425
+def update_scripts
  426
+  `adb shell mkdir -p #{scripts_path}` if !device_path_exists?(scripts_path)
  427
+  puts "Pushing files to apk public file area."
  428
+  last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
  429
+  Dir.chdir('src') do
  430
+    Dir["**/*.rb"].each do |script_file|
  431
+      next if File.directory? script_file
  432
+      next if File.mtime(script_file) < last_update
  433
+      next if script_file =~ /~$/
  434
+      print "#{script_file}: "; $stdout.flush
  435
+      `adb push #{script_file} #{scripts_path}/#{script_file}`
  436
+    end
  437
+  end
  438
+  mark_update
  439
+end
  440
+
  441
+def start_app
  442
+  `adb shell am start -a android.intent.action.MAIN -n #{package}/.#{main_activity}`
  443
+end
  444
+
  445
+def stop_app
  446
+  output = `adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
  447
+  return output !~ /Operation not permitted/
  448
+end
44  src/org/ruboto/EntryPointActivity.java
... ...
@@ -1,10 +1,5 @@
1 1
 package org.ruboto;
2 2
 
3  
-import java.io.File;
4  
-import java.io.IOException;
5  
-
6  
-import org.ruboto.Script;
7  
-
8 3
 import android.app.ProgressDialog;
9 4
 import android.content.BroadcastReceiver;
10 5
 import android.content.Context;
@@ -14,8 +9,6 @@
14 9
 import android.content.IntentFilter;
15 10
 import android.net.Uri;
16 11
 import android.os.Bundle;
17  
-import android.os.Handler;
18  
-import android.util.Log;
19 12
 import android.view.View;
20 13
 import android.widget.TextView;
21 14
 import android.widget.Toast;
@@ -28,7 +21,7 @@
28 21
     protected boolean appStarted = false;
29 22
 
30 23
 	public void onCreate(Bundle bundle) {
31  
-        Log.d("RUBOTO", "onCreate: ");
  24
+        Log.d("onCreate: ");
32 25
 
33 26
 	    try {
34 27
     		splash = Class.forName(getPackageName() + ".R$layout").getField("splash").getInt(null);
@@ -36,32 +29,32 @@ public void onCreate(Bundle bundle) {
36 29
 		    splash = -1;
37 30
 		}
38 31
 
39  
-        if (Script.isInitialized()) {
  32
+        if (JRubyAdapter.isInitialized()) {
40 33
             appStarted = true;
41 34
 		}
42 35
 	    super.onCreate(bundle);
43 36
 	}
44 37
 
45 38
     public void onResume() {
46  
-        Log.d("RUBOTO", "onResume: ");
  39
+        Log.d("onResume: ");
47 40
 
48 41
         if(appStarted) {
49  
-            Log.d("RUBOTO", "onResume: App already started!");
  42
+            Log.d("onResume: App already started!");
50 43
             super.onResume();
51 44
             return;
52 45
         }
53 46
 
54  
-        Log.d("RUBOTO", "onResume: Checking JRuby");
55  
-        if (Script.isInitialized()) {
56  
-            Log.d("RUBOTO", "Already initialized");
  47
+        Log.d("onResume: Checking JRuby");
  48
+        if (JRubyAdapter.isInitialized()) {
  49
+            Log.d("Already initialized");
57 50
     	    fireRubotoActivity();
58 51
         } else {
59  
-            Log.d("RUBOTO", "Not initialized");
  52
+            Log.d("Not initialized");
60 53
             showProgress();
61 54
             receiver = new BroadcastReceiver(){
62 55
                 public void onReceive(Context context, Intent intent) {
63  
-                    Log.i("RUBOTO", "received broadcast: " + intent);
64  
-                    Log.i("RUBOTO", "URI: " + intent.getData());
  56
+                    Log.i("received broadcast: " + intent);
  57
+                    Log.i("URI: " + intent.getData());
65 58
                     if (intent.getData().toString().equals("package:org.ruboto.core")) {
66 59
                         Toast.makeText(context,"Ruboto Core is now installed.",Toast.LENGTH_SHORT).show();
67 60
                         if (receiver != null) {
@@ -82,7 +75,7 @@ public void onReceive(Context context, Intent intent) {
82 75
     }
83 76
 
84 77
     public void onPause() {
85  
-        Log.d("RUBOTO", "onPause: ");
  78
+        Log.d("onPause: ");
86 79
 
87 80
         if (receiver != null) {
88 81
     	    unregisterReceiver(receiver);
@@ -92,7 +85,7 @@ public void onPause() {
92 85
     }
93 86
 
94 87
     public void onDestroy() {
95  
-        Log.d("RUBOTO", "onDestroy: ");
  88
+        Log.d("onDestroy: ");
96 89
 
97 90
         super.onDestroy();
98 91
         if (dialogCancelled) {
@@ -104,9 +97,9 @@ public void onDestroy() {
104 97
     private void initJRuby(final boolean firstTime) {
105 98
         new Thread(new Runnable() {
106 99
             public void run() {
107  
-                final boolean jrubyOk = Script.setUpJRuby(EntryPointActivity.this);
  100
+                final boolean jrubyOk = JRubyAdapter.setUpJRuby(EntryPointActivity.this);
108 101
                 if (jrubyOk) {
109  
-                    Log.d("RUBOTO", "onResume: JRuby OK");
  102
+                    Log.d("onResume: JRuby OK");
110 103
                     prepareJRuby();
111 104
                     runOnUiThread(new Runnable() {
112 105
                         public void run() {
@@ -117,7 +110,7 @@ public void run() {
117 110
                     runOnUiThread(new Runnable() {
118 111
                         public void run() {
119 112
                             if (firstTime) {
120  
-                                Log.d("RUBOTO", "onResume: Checking JRuby - IN UI thread");
  113
+                                Log.d("onResume: Checking JRuby - IN UI thread");
121 114
                                 try {
122 115
                                     setContentView(Class.forName(getPackageName() + ".R$layout").getField("get_ruboto_core").getInt(null));
123 116
                                 } catch (Exception e) {
@@ -147,7 +140,6 @@ public void getRubotoCore(View view) {
147 140
             startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("market://details?id=org.ruboto.core")));
148 141
         } catch (android.content.ActivityNotFoundException anfe) {
149 142
             try {
150  
-                TextView textView = (TextView) findViewById(Class.forName(getPackageName() + ".R$id").getField("text").getInt(null));
151 143
                 Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(RUBOTO_URL));
152 144
                 startActivity(intent);
153 145
             } catch (Exception e) {}
@@ -157,7 +149,7 @@ public void getRubotoCore(View view) {
157 149
     protected void fireRubotoActivity() {
158 150
         if(appStarted) return;
159 151
         appStarted = true;
160  
-        Log.i("RUBOTO", "Starting activity");
  152
+        Log.i("Starting activity");
161 153
         loadScript();
162 154
         onStart();
163 155
         super.onResume();
@@ -166,7 +158,7 @@ protected void fireRubotoActivity() {
166 158
 
167 159
     private void showProgress() {
168 160
         if (loadingDialog == null) {
169  
-            Log.i("RUBOTO", "Showing progress");
  161
+            Log.i("Showing progress");
170 162
             if (splash > 0) {
171 163
                 requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
172 164
                 setContentView(splash);
@@ -185,7 +177,7 @@ public void onCancel(DialogInterface dialog) {
185 177
 
186 178
     private void hideProgress() {
187 179
         if (loadingDialog != null) {
188  
-            Log.d("RUBOTO", "Hide progress");
  180
+            Log.d("Hide progress");
189 181
             loadingDialog.dismiss();
190 182
             loadingDialog = null;
191 183
         }
476  src/org/ruboto/JRubyAdapter.java
... ...
@@ -0,0 +1,476 @@
  1
+package org.ruboto;
  2
+
  3
+import java.io.File;
  4
+import java.io.FilenameFilter;
  5
+import java.io.PrintStream;
  6
+import java.lang.reflect.InvocationTargetException;
  7
+import java.lang.reflect.Method;
  8
+
  9
+import android.content.Context;
  10
+import android.content.pm.ApplicationInfo;
  11
+import android.content.pm.PackageInfo;
  12
+import android.content.pm.PackageManager;
  13
+import android.content.pm.PackageManager.NameNotFoundException;
  14
+import android.os.Environment;
  15
+import dalvik.system.PathClassLoader;
  16
+
  17
+public class JRubyAdapter {
  18
+    private static Object ruby;
  19
+    private static boolean isDebugBuild = false;
  20
+    private static PrintStream output = null;
  21
+    private static boolean initialized = false;
  22
+
  23
+    private static String localContextScope = "SINGLETON";
  24
+    private static String localVariableBehavior = "TRANSIENT";
  25
+