Permalink
Browse files

* Updated to Ruboto 0.7.0.dev

  • Loading branch information...
1 parent b0f26cd commit 6aa646e982dcf808c6671ac0dbb916311d0398d1 @donv donv committed Jul 3, 2012
View
38 AndroidManifest.xml
@@ -1,9 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
-<manifest xmlns:android='http://schemas.android.com/apk/res/android' android:versionName='@string/version_name' package='org.ruboto.irb'
- android:versionCode='12' android:installLocation='preferExternal'>
- <application android:hardwareAccelerated='true' android:label='@string/app_name' android:icon='@drawable/icon' android:largeHeap='true'>
- <activity android:name='IRB' android:label='@string/app_name' android:windowSoftInputMode='adjustResize'
- android:configChanges='orientation|screenSize' android:alwaysRetainTaskState="true">
+<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'>
+ <application android:hardwareAccelerated='true' android:largeHeap='true' android:icon='@drawable/icon' android:label='@string/app_name'>
+ <activity android:name='IRB' android:alwaysRetainTaskState='true' android:windowSoftInputMode='adjustResize' android:configChanges='orientation|screenSize' android:label='@string/app_name'>
<intent-filter>
<action android:name='android.intent.action.MAIN'/>
<category android:name='android.intent.category.LAUNCHER'/>
@@ -29,23 +27,23 @@
<category android:name='android.intent.category.DEFAULT'/>
</intent-filter>
</activity>
- <activity android:name='org.ruboto.RubotoActivity' android:configChanges='orientation|screenSize' android:alwaysRetainTaskState="true"/>
- <activity android:name='org.ruboto.RubotoDialog' android:theme='@android:style/Theme.Dialog' android:configChanges='orientation|screenSize'/>
+ <activity android:name='org.ruboto.RubotoActivity' android:alwaysRetainTaskState='true' android:configChanges='orientation|screenSize'/>
+ <activity android:theme='@android:style/Theme.Dialog' android:name='org.ruboto.RubotoDialog' android:configChanges='orientation|screenSize'/>
<activity android:name='org.ruboto.RubotoPreferenceActivity'/>
<service android:name='org.ruboto.RubotoService' android:exported='false'/>
</application>
- <uses-sdk android:minSdkVersion='5' android:targetSdkVersion='13'/>
- <supports-screens android:smallScreens='true' android:normalScreens='true' android:largeScreens='true' android:xlargeScreens='true' android:anyDensity='true'/>
- <uses-feature android:required='false' android:name='android.hardware.telephony'/>
- <uses-feature android:required='false' android:name='android.hardware.touchscreen'/>
- <uses-feature android:required='false' android:name='android.hardware.location'/>
- <uses-feature android:required='false' android:name='android.hardware.location.gps'/>
- <uses-feature android:required='false' android:name='android.hardware.location.network'/>
- <uses-feature android:required='false' android:name='android.hardware.wifi'/>
- <uses-feature android:required='false' android:name='android.hardware.microphone'/>
- <uses-feature android:required='false' android:name='android.hardware.camera'/>
- <uses-feature android:required='false' android:name='android.hardware.camera.autofocus'/>
- <uses-feature android:required='false' android:name='android.hardware.bluetooth'/>
+ <uses-sdk android:minSdkVersion='7' android:targetSdkVersion='13'/>
+ <supports-screens android:normalScreens='true' android:largeScreens='true' android:xlargeScreens='true' android:anyDensity='true' android:smallScreens='true'/>
+ <uses-feature android:name='android.hardware.telephony' android:required='false'/>
+ <uses-feature android:name='android.hardware.touchscreen' android:required='false'/>
+ <uses-feature android:name='android.hardware.location' android:required='false'/>
+ <uses-feature android:name='android.hardware.location.gps' android:required='false'/>
+ <uses-feature android:name='android.hardware.location.network' android:required='false'/>
+ <uses-feature android:name='android.hardware.wifi' android:required='false'/>
+ <uses-feature android:name='android.hardware.microphone' android:required='false'/>
+ <uses-feature android:name='android.hardware.camera' android:required='false'/>
+ <uses-feature android:name='android.hardware.camera.autofocus' android:required='false'/>
+ <uses-feature android:name='android.hardware.bluetooth' android:required='false'/>
<uses-permission android:name='android.permission.WRITE_EXTERNAL_STORAGE'/>
<uses-permission android:name='com.android.launcher.permission.INSTALL_SHORTCUT'/>
<uses-permission android:name='android.permission.INTERNET'/>
@@ -64,4 +62,4 @@
<uses-permission android:name='android.permission.RECORD_AUDIO'/>
<uses-permission android:name='android.permission.CAMERA'/>
<uses-permission android:name='android.permission.BLUETOOTH'/>
-</manifest>
+</manifest>
View
409 Rakefile
@@ -1,407 +1,2 @@
-if `ant -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.to_i == 1 && $2.to_i < 8)
- puts "ANT version 1.8.0 or later required. Version found: #{$1}.#{$2}.#{$3}"
- exit 1
-end
-
-require 'time'
-
-def manifest() @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
-def package() manifest.root.attribute('package') end
-def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
-def scripts_path() @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
-def app_files_path() @app_files_path ||= "/data/data/#{package}/files" end
-
-require 'rake/clean'
-require 'rexml/document'
-
-PROJECT_DIR = Dir.getwd
-UPDATE_MARKER_FILE = File.expand_path(File.join('bin', 'LAST_UPDATE'), File.dirname(__FILE__))
-BUNDLE_JAR = File.expand_path 'libs/bundle.jar'
-BUNDLE_PATH = File.expand_path 'bin/bundle'
-MANIFEST_FILE = File.expand_path 'AndroidManifest.xml'
-RUBOTO_CONFIG_FILE = File.expand_path 'ruboto.yml'
-GEM_FILE = File.expand_path('Gemfile.apk')
-GEM_LOCK_FILE = File.expand_path('Gemfile.apk.lock')
-RELEASE_APK_FILE = File.expand_path "bin/#{build_project_name}-release.apk"
-APK_FILE = File.expand_path "bin/#{build_project_name}-debug.apk"
-TEST_APK_FILE = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
-JRUBY_JARS = Dir[File.expand_path 'libs/jruby-*.jar']
-RESOURCE_FILES = Dir[File.expand_path 'res/**/*']
-JAVA_SOURCE_FILES = Dir[File.expand_path 'src/**/*.java']
-RUBY_SOURCE_FILES = Dir[File.expand_path 'src/**/*.rb']
-APK_DEPENDENCIES = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
-KEYSTORE_FILE = (key_store = File.readlines('ant.properties').grep(/^key.store=/).first) ? key_store.chomp.sub(/^key.store=/, '') : "#{build_project_name}.keystore"
-KEYSTORE_ALIAS = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
-
-CLEAN.include('bin')
-
-task :default => :debug
-
-file JRUBY_JARS => RUBOTO_CONFIG_FILE do
- next unless File.exists? RUBOTO_CONFIG_FILE
- jruby_jars_mtime = JRUBY_JARS.map { |f| File.mtime(f) }.min
- ruboto_yml_mtime = File.mtime(RUBOTO_CONFIG_FILE)
- next if jruby_jars_mtime > ruboto_yml_mtime
- puts '*' * 80
- if JRUBY_JARS.empty?
- puts ' The JRuby jars are missing.'
- else
- puts " The JRuby jars need reconfiguring after changes to #{RUBOTO_CONFIG_FILE}"
- puts " #{RUBOTO_CONFIG_FILE}: #{ruboto_yml_mtime}"
- puts " #{JRUBY_JARS.join(', ')}: #{jruby_jars_mtime}"
- end
- puts ' Run "ruboto update jruby" to regenerate the JRuby jars'
- puts '*' * 80
-end
-
-desc 'build debug package'
-task :debug => APK_FILE
-
-namespace :debug do
- desc 'build debug package if compiled files have changed'
- task :quick => [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES do |t|
- build_apk(t, false)
- end
-end
-
-desc "build package and install it on the emulator or device"
-task :install => APK_FILE do
- install_apk
-end
-
-namespace :install do
- desc 'uninstall, build, and install the application'
- task :clean => [:uninstall, APK_FILE, :install]
-
- desc 'Install the application, but only if compiled files are changed.'
- task :quick => 'debug:quick' do
- install_apk
- end
-end
-
-desc 'Build APK for release'
-task :release => RELEASE_APK_FILE
-
-file RELEASE_APK_FILE => [KEYSTORE_FILE] + APK_DEPENDENCIES do |t|
- build_apk(t, true)
-end
-
-desc 'Create a keystore for signing the release APK'
-file KEYSTORE_FILE do
- unless File.read('ant.properties') =~ /^key.store=/
- File.open('ant.properties', 'a'){|f| f << "\nkey.store=#{KEYSTORE_FILE}\n"}
- end
- unless File.read('ant.properties') =~ /^key.alias=/
- File.open('ant.properties', 'a'){|f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n"}
- end
- sh "keytool -genkey -v -keystore #{KEYSTORE_FILE} -alias #{KEYSTORE_ALIAS} -keyalg RSA -keysize 2048 -validity 10000"
-end
-
-desc 'Tag this working copy with the current version'
-task :tag => :release do
- unless `git branch` =~ /^\* master$/
- puts "You must be on the master branch to release!"
- exit!
- end
- # sh "git commit --allow-empty -a -m 'Release #{version}'"
- output = `git status --porcelain`
- raise "Workspace not clean!\n#{output}" unless output.empty?
- sh "git tag #{version}"
- sh "git push origin master --tags"
-end
-
-task :sign => :release do
- sh "jarsigner -keystore #{ENV['RUBOTO_KEYSTORE']} -signedjar bin/#{build_project_name}.apk bin/#{build_project_name}-unsigned.apk #{ENV['RUBOTO_KEY_ALIAS']}"
-end
-
-task :align => :sign do
- sh "zipalign 4 bin/#{build_project_name}.apk #{build_project_name}.apk"
-end
-
-task :publish => :align do
- puts "#{build_project_name}.apk is ready for the market!"
-end
-
-desc 'Start the emulator with larger disk'
-task :emulator do
- sh 'emulator -partition-size 1024 -avd Android_3.0'
-end
-
-task :start do
- start_app
-end
-
-task :stop do
- raise "Unable to stop app. Only available on emulator." unless stop_app
-end
-
-desc 'Restart the application'
-task :restart => [:stop, :start]
-
-task :uninstall do
- uninstall_apk
-end
-
-file MANIFEST_FILE
-file RUBOTO_CONFIG_FILE
-
-file APK_FILE => APK_DEPENDENCIES do |t|
- build_apk(t, false)
-end
-
-desc 'Copy scripts to emulator or device'
-task :update_scripts => ['install:quick'] do
- update_scripts
-end
-
-namespace :update_scripts do
- desc 'Copy scripts to emulator and restart the app'
- task :restart => APK_DEPENDENCIES do |t|
- if build_apk(t, false) || !stop_app
- install_apk
- else
- update_scripts
- end
- start_app
- end
-end
-
-task :test => :uninstall do
- Dir.chdir('test') do
- puts 'Running tests'
- sh "adb uninstall #{package}.tests"
- sh "ant instrument install test"
- end
-end
-
-namespace :test do
- task :quick => :update_scripts do
- Dir.chdir('test') do
- puts 'Running quick tests'
- sh 'ant instrument'
- sh 'ant installi'
- sh "ant run-tests-quick"
- end
- end
-end
-
-file GEM_FILE
-file GEM_LOCK_FILE
-
-desc 'Generate bundle jar from Gemfile'
-task :bundle => BUNDLE_JAR
-
-file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
- next unless File.exists? GEM_FILE
- puts "Generating #{BUNDLE_JAR}"
-
- FileUtils.mkdir_p BUNDLE_PATH
- sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH}"
- gem_path = Dir["#{BUNDLE_PATH}/*ruby/1.8/gems"][0]
-
- if package != 'org.ruboto.core' && JRUBY_JARS.none? { |f| File.exists? f }
- Dir.chdir gem_path do
- Dir['activerecord-jdbc-adapter-*'].each do |g|
- puts "Removing #{g} gem since it is included in the RubotoCore platform apk."
- FileUtils.rm_rf g
- end
- end
- end
-
- # Remove duplicate files
- Dir.chdir gem_path do
- scanned_files = []
- source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
- Dir["*/lib/**/*"].each do |f|
- next if File.directory? f
- raise "Malformed file name" unless f =~ %r{^(.*?)/lib/(.*)$}
- gem_name, lib_file = $1, $2
- if existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} }
- puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
- FileUtils.rm existing_file
- scanned_files.delete existing_file
- elsif source_files.include? lib_file
- puts "Removing duplicate file #{lib_file} in gem #{gem_name}"
- puts "Already present in project source src/#{lib_file}"
- FileUtils.rm f
- next
- end
- scanned_files << f
- end
- end
-
- # Expand JARs
- Dir.chdir gem_path do
- Dir['*'].each do |gem_lib|
- Dir.chdir "#{gem_lib}/lib" do
- Dir['**/*.jar'].each do |jar|
- unless jar =~ /sqlite-jdbc/
- puts "Expanding #{gem_lib} #{jar} into #{BUNDLE_JAR}"
- `jar xf #{jar}`
- end
- if jar == 'arjdbc/jdbc/adapter_java.jar'
- jar_load_code = <<-END_CODE
-require 'jruby'
-Java::arjdbc.jdbc.AdapterJavaService.new.basicLoad(JRuby.runtime)
- END_CODE
- else
- jar_load_code = ''
- end
- puts "Writing dummy JAR file #{jar + '.rb'}"
- File.open(jar + '.rb', 'w') { |f| f << jar_load_code }
- if jar.end_with?('.jar')
- puts "Writing dummy JAR file #{jar.sub(/.jar$/, '.rb')}"
- File.open(jar.sub(/.jar$/, '.rb'), 'w') { |f| f << jar_load_code }
- end
- FileUtils.rm_f(jar)
- end
- end
- end
- end
-
-
- FileUtils.rm_f BUNDLE_JAR
- Dir["#{gem_path}/*"].each_with_index do |gem_dir, i|
- `jar #{i == 0 ? 'c' : 'u'}f #{BUNDLE_JAR} -C #{gem_dir}/lib .`
- end
- FileUtils.rm_rf BUNDLE_PATH
-end
-
-# Methods
-
-def mark_update(time = Time.now)
- FileUtils.mkdir_p File.dirname(UPDATE_MARKER_FILE)
- File.open(UPDATE_MARKER_FILE, 'w') { |f| f << time.iso8601 }
-end
-
-def clear_update
- mark_update File.ctime APK_FILE
- if device_path_exists?(scripts_path)
- sh "adb shell rm -r #{scripts_path}"
- puts "Deleted scripts directory #{scripts_path}"
- end
-end
-
-def strings(name)
- @strings ||= REXML::Document.new(File.read('res/values/strings.xml'))
- value = @strings.elements["//string[@name='#{name.to_s}']"] or raise "string '#{name}' not found in strings.xml"
- value.text
-end
-
-def version()
- strings :version_name
-end
-
-def app_name()
- strings :app_name
-end
-
-def main_activity()
- manifest.root.elements['application'].elements["activity[@android:label='@string/app_name']"].attribute('android:name')
-end
-
-def device_path_exists?(path)
- path_output =`adb shell ls #{path}`
- result = path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
- result
-end
-
-def package_installed? test = false
- package_name = "#{package}#{'.tests' if test}"
- ['', '-0', '-1', '-2'].each do |i|
- p = "/data/app/#{package_name}#{i}.apk"
- o = `adb shell ls -l #{p}`.chomp
- if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(p)}$/
- apk_file = test ? TEST_APK_FILE : APK_FILE
- if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
- return true
- else
- return false
- end
- end
- end
- return nil
-end
-
-private
-
-def replace_faulty_code(faulty_file, faulty_code)
- explicit_requires = Dir["#{faulty_file.chomp('.rb')}/*.rb"].sort.map { |f| File.basename(f) }.map do |filename|
- "require 'active_model/validations/#{filename}'"
- end.join("\n")
-
- old_code = File.read(faulty_file)
- new_code = old_code.gsub faulty_code, explicit_requires
- if new_code != old_code
- puts "Replaced directory listing code in file #{faulty_file} with explicit requires."
- File.open(faulty_file, 'w') { |f| f << new_code }
- else
- puts "Could not find expected faulty code\n\n#{faulty_code}\n\nin file #{faulty_file}\n\n#{old_code}\n\n"
- end
-end
-
-def build_apk(t, release)
- apk_file = release ? RELEASE_APK_FILE : APK_FILE
- if File.exist?(apk_file)
- changed_prereqs = t.prerequisites.select do |p|
- File.file?(p) && !Dir[p].empty? && Dir[p].map { |f| File.mtime(f) }.max > File.mtime(APK_FILE)
- end
- return false if changed_prereqs.empty?
- changed_prereqs.each { |f| puts "#{f} changed." }
- puts "Forcing rebuild of #{apk_file}."
- end
- if release
- sh 'ant release'
- else
- sh 'ant debug'
- end
- return true
-end
-
-def install_apk
- case package_installed?
- when true
- puts "Package already installed."
- return
- when false
- puts "Package installed, but of wrong size."
- end
- sh 'ant installd'
- clear_update
-end
-
-def uninstall_apk
- return if package_installed?.nil?
- puts "Uninstalling package #{package}"
- system "adb uninstall #{package}"
- if $? != 0 && package_installed?
- puts "Uninstall failed exit code #{$?}"
- exit $?
- end
-end
-
-def update_scripts
- `adb shell mkdir -p #{scripts_path}` if !device_path_exists?(scripts_path)
- puts "Pushing files to apk public file area."
- last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
- # TODO(uwe): Use `adb sync src` instead?
- Dir.chdir('src') do
- Dir["**/*.rb"].each do |script_file|
- next if File.directory? script_file
- next if File.mtime(script_file) < last_update
- next if script_file =~ /~$/
- print "#{script_file}: "; $stdout.flush
- `adb push #{script_file} #{scripts_path}/#{script_file}`
- end
- end
- mark_update
-end
-
-def start_app
- `adb shell am start -a android.intent.action.MAIN -n #{package}/.#{main_activity}`
-end
-
-def stop_app
- output = `adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
- return output !~ /Operation not permitted/
-end
+# Write your own rake tasks here.
+# You can find the Ruboto rake tasks in rakelib/ruboto.rake
View
41 build.xml
@@ -4,7 +4,7 @@
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
- <loadproperties srcFile="local.properties" />
+ <property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
@@ -28,6 +28,15 @@
-->
<property file="ant.properties" />
+ <!-- if sdk.dir was not set from one of the property file, then
+ get it from the ANDROID_HOME env var.
+ This must be done before we load project.properties since
+ the proguard config can use sdk.dir -->
+ <property environment="env" />
+ <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+ <isset property="env.ANDROID_HOME" />
+ </condition>
+
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
@@ -41,25 +50,23 @@
<!-- quick check on sdk.dir -->
<fail
- message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
+ 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."
unless="sdk.dir"
/>
-
-<!-- extension targets. Uncomment the ones where you want to do custom work
- in between standard targets -->
-<!--
- <target name="-pre-build">
- </target>
- <target name="-pre-compile">
- </target>
-
- /* This is typically used for code obfuscation.
- Compiled code location: ${out.classes.absolute.dir}
- If this is not done in place, override ${out.dex.input.absolute.dir} */
- <target name="-post-compile">
- </target>
--->
+ <!--
+ Import per project custom build rules if present at the root of the project.
+ This is the place to put custom intermediary targets such as:
+ -pre-build
+ -pre-compile
+ -post-compile (This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir})
+ -post-package
+ -post-build
+ -pre-clean
+ -->
+ <import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
View
20 proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
View
448 rakelib/ruboto.rake
@@ -0,0 +1,448 @@
+if `ant -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.to_i == 1 && $2.to_i < 8)
+ puts "ANT version 1.8.0 or later required. Version found: #{$1}.#{$2}.#{$3}"
+ exit 1
+end
+
+require 'time'
+
+def manifest() @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
+def package() manifest.root.attribute('package') end
+def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
+def scripts_path() @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
+def app_files_path() @app_files_path ||= "/data/data/#{package}/files" end
+
+require 'rake/clean'
+require 'rexml/document'
+
+PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
+UPDATE_MARKER_FILE = File.join(PROJECT_DIR, 'bin', 'LAST_UPDATE')
+BUNDLE_JAR = File.expand_path 'libs/bundle.jar'
+BUNDLE_PATH = File.expand_path 'bin/bundle'
+MANIFEST_FILE = File.expand_path 'AndroidManifest.xml'
+PROJECT_PROPS_FILE = File.expand_path 'project.properties'
+RUBOTO_CONFIG_FILE = File.expand_path 'ruboto.yml'
+GEM_FILE = File.expand_path('Gemfile.apk')
+GEM_LOCK_FILE = File.expand_path('Gemfile.apk.lock')
+RELEASE_APK_FILE = File.expand_path "bin/#{build_project_name}-release.apk"
+APK_FILE = File.expand_path "bin/#{build_project_name}-debug.apk"
+TEST_APK_FILE = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
+JRUBY_JARS = Dir[File.expand_path 'libs/jruby-*.jar']
+RESOURCE_FILES = Dir[File.expand_path 'res/**/*']
+JAVA_SOURCE_FILES = Dir[File.expand_path 'src/**/*.java']
+RUBY_SOURCE_FILES = Dir[File.expand_path 'src/**/*.rb']
+APK_DEPENDENCIES = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
+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"
+KEYSTORE_ALIAS = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
+
+CLEAN.include('bin')
+
+task :default => :debug
+
+file JRUBY_JARS => RUBOTO_CONFIG_FILE do
+ next unless File.exists? RUBOTO_CONFIG_FILE
+ jruby_jars_mtime = JRUBY_JARS.map { |f| File.mtime(f) }.min
+ ruboto_yml_mtime = File.mtime(RUBOTO_CONFIG_FILE)
+ next if jruby_jars_mtime > ruboto_yml_mtime
+ puts '*' * 80
+ if JRUBY_JARS.empty?
+ puts ' The JRuby jars are missing.'
+ else
+ puts " The JRuby jars need reconfiguring after changes to #{RUBOTO_CONFIG_FILE}"
+ puts " #{RUBOTO_CONFIG_FILE}: #{ruboto_yml_mtime}"
+ puts " #{JRUBY_JARS.join(', ')}: #{jruby_jars_mtime}"
+ end
+ puts ' Run "ruboto update jruby" to regenerate the JRuby jars'
+ puts '*' * 80
+end
+
+desc 'build debug package'
+task :debug => APK_FILE
+
+namespace :debug do
+ desc 'build debug package if compiled files have changed'
+ task :quick => [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES do |t|
+ build_apk(t, false)
+ end
+end
+
+desc "build package and install it on the emulator or device"
+task :install => APK_FILE do
+ install_apk
+end
+
+namespace :install do
+ desc 'uninstall, build, and install the application'
+ task :clean => [:uninstall, APK_FILE, :install]
+
+ desc 'Install the application, but only if compiled files are changed.'
+ task :quick => 'debug:quick' do
+ install_apk
+ end
+end
+
+desc 'Build APK for release'
+task :release => RELEASE_APK_FILE
+
+file RELEASE_APK_FILE => [KEYSTORE_FILE] + APK_DEPENDENCIES do |t|
+ build_apk(t, true)
+end
+
+desc 'Create a keystore for signing the release APK'
+file KEYSTORE_FILE do
+ unless File.read('ant.properties') =~ /^key.store=/
+ File.open('ant.properties', 'a'){|f| f << "\nkey.store=#{KEYSTORE_FILE}\n"}
+ end
+ unless File.read('ant.properties') =~ /^key.alias=/
+ File.open('ant.properties', 'a'){|f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n"}
+ end
+ sh "keytool -genkey -v -keystore #{KEYSTORE_FILE} -alias #{KEYSTORE_ALIAS} -keyalg RSA -keysize 2048 -validity 10000"
+end
+
+desc 'Tag this working copy with the current version'
+task :tag => :release do
+ unless `git branch` =~ /^\* master$/
+ puts "You must be on the master branch to release!"
+ exit!
+ end
+ # sh "git commit --allow-empty -a -m 'Release #{version}'"
+ output = `git status --porcelain`
+ raise "Workspace not clean!\n#{output}" unless output.empty?
+ sh "git tag #{version}"
+ sh "git push origin master --tags"
+end
+
+task :sign => :release do
+ sh "jarsigner -keystore #{ENV['RUBOTO_KEYSTORE']} -signedjar bin/#{build_project_name}.apk bin/#{build_project_name}-unsigned.apk #{ENV['RUBOTO_KEY_ALIAS']}"
+end
+
+task :align => :sign do
+ sh "zipalign 4 bin/#{build_project_name}.apk #{build_project_name}.apk"
+end
+
+task :publish => :align do
+ puts "#{build_project_name}.apk is ready for the market!"
+end
+
+desc 'Start the emulator with larger disk'
+task :emulator do
+ sh 'emulator -partition-size 1024 -avd Android_3.0'
+end
+
+task :start do
+ start_app
+end
+
+task :stop do
+ raise "Unable to stop app. Only available on emulator." unless stop_app
+end
+
+desc 'Restart the application'
+task :restart => [:stop, :start]
+
+task :uninstall do
+ uninstall_apk
+end
+
+file PROJECT_PROPS_FILE
+file MANIFEST_FILE => PROJECT_PROPS_FILE do
+ sdk_level = File.read(PROJECT_PROPS_FILE).scan(/(?:target=android-)(\d+)/)[0][0].to_i
+ old_manifest = File.read(MANIFEST_FILE)
+ manifest = old_manifest.dup
+ manifest.sub!(/(android:minSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
+ manifest.sub!(/(android:targetSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
+ File.open(MANIFEST_FILE, 'w'){|f| f << manifest} if manifest != old_manifest
+end
+
+file RUBOTO_CONFIG_FILE
+
+file APK_FILE => APK_DEPENDENCIES do |t|
+ build_apk(t, false)
+end
+
+desc 'Copy scripts to emulator or device'
+task :update_scripts => ['install:quick'] do
+ update_scripts
+end
+
+namespace :update_scripts do
+ desc 'Copy scripts to emulator and restart the app'
+ task :restart => APK_DEPENDENCIES do |t|
+ if build_apk(t, false) || !stop_app
+ install_apk
+ else
+ update_scripts
+ end
+ start_app
+ end
+end
+
+task :test => :uninstall do
+ Dir.chdir('test') do
+ puts 'Running tests'
+ sh "adb uninstall #{package}.tests"
+ sh "ant instrument install test"
+ end
+end
+
+namespace :test do
+ task :quick => :update_scripts do
+ Dir.chdir('test') do
+ puts 'Running quick tests'
+ sh 'ant instrument'
+ sh 'ant installi'
+ sh "ant run-tests-quick"
+ end
+ end
+end
+
+file GEM_FILE
+file GEM_LOCK_FILE
+
+desc 'Generate bundle jar from Gemfile'
+task :bundle => BUNDLE_JAR
+
+file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
+ next unless File.exists? GEM_FILE
+ puts "Generating #{BUNDLE_JAR}"
+
+ FileUtils.mkdir_p BUNDLE_PATH
+ sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH}"
+ gem_path = Dir["#{BUNDLE_PATH}/*ruby/1.8/gems"][0]
+
+ if package != 'org.ruboto.core' && JRUBY_JARS.none? { |f| File.exists? f }
+ Dir.chdir gem_path do
+ Dir['{activerecord-jdbc-adapter, jruby-openssl}-*'].each do |g|
+ puts "Removing #{g} gem since it is included in the RubotoCore platform apk."
+ FileUtils.rm_rf g
+ end
+ end
+ else
+ Dir.chdir gem_path do
+ Dir['jruby-openssl-*/lib'].each do |g|
+ rel_dir = "#{g}/lib/ruby"
+ unless File.exists? rel_dir
+ puts "Relocating #{g} files to match standard load path."
+ dirs = Dir["#{g}/*"]
+ FileUtils.mkdir_p rel_dir
+ dirs.each do |d|
+ FileUtils.move d, rel_dir
+ end
+ end
+ end
+ end
+ end
+
+ # Remove duplicate files
+ Dir.chdir gem_path do
+ scanned_files = []
+ source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
+ Dir["*/lib/**/*"].each do |f|
+ next if File.directory? f
+ raise "Malformed file name" unless f =~ %r{^(.*?)/lib/(.*)$}
+ gem_name, lib_file = $1, $2
+ if existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} }
+ puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
+ FileUtils.rm existing_file
+ scanned_files.delete existing_file
+ elsif source_files.include? lib_file
+ puts "Removing duplicate file #{lib_file} in gem #{gem_name}"
+ puts "Already present in project source src/#{lib_file}"
+ FileUtils.rm f
+ next
+ end
+ scanned_files << f
+ end
+ end
+
+ # Expand JARs
+ Dir.chdir gem_path do
+ Dir['*'].each do |gem_lib|
+ Dir.chdir "#{gem_lib}/lib" do
+ Dir['**/*.jar'].each do |jar|
+ if jar == 'arjdbc/jdbc/adapter_java.jar'
+ jar_load_code = <<-END_CODE
+require 'jruby'
+Java::arjdbc.jdbc.AdapterJavaService.new.basicLoad(JRuby.runtime)
+ END_CODE
+ elsif jar =~ /shared\/jopenssl.jar$/
+ jar_load_code = <<-END_CODE
+require 'jruby'
+puts 'Starting JRuby OpenSSL Service'
+public
+Java::JopensslService.new.basicLoad(JRuby.runtime)
+ END_CODE
+ else
+ jar_load_code = ''
+ end
+ unless jar =~ /sqlite-jdbc/
+ puts "Expanding #{gem_lib} #{jar} into #{BUNDLE_JAR}"
+ `jar xf #{jar}`
+ end
+ puts "Writing dummy JAR file #{jar + '.rb'}"
+ File.open(jar + '.rb', 'w') { |f| f << jar_load_code }
+ if jar.end_with?('.jar')
+ puts "Writing dummy JAR file #{jar.sub(/.jar$/, '.rb')}"
+ File.open(jar.sub(/.jar$/, '.rb'), 'w') { |f| f << jar_load_code }
+ end
+ FileUtils.rm_f(jar)
+ end
+ end
+ end
+ end
+
+
+ FileUtils.rm_f BUNDLE_JAR
+ Dir["#{gem_path}/*"].each_with_index do |gem_dir, i|
+ `jar #{i == 0 ? 'c' : 'u'}f #{BUNDLE_JAR} -C #{gem_dir}/lib .`
+ end
+ FileUtils.rm_rf BUNDLE_PATH
+end
+
+# Methods
+
+def mark_update(time = Time.now)
+ FileUtils.mkdir_p File.dirname(UPDATE_MARKER_FILE)
+ File.open(UPDATE_MARKER_FILE, 'w') { |f| f << time.iso8601 }
+end
+
+def clear_update
+ mark_update File.ctime APK_FILE
+ if device_path_exists?(scripts_path)
+ sh "adb shell rm -r #{scripts_path}"
+ puts "Deleted scripts directory #{scripts_path}"
+ end
+end
+
+def strings(name)
+ @strings ||= REXML::Document.new(File.read('res/values/strings.xml'))
+ value = @strings.elements["//string[@name='#{name.to_s}']"] or raise "string '#{name}' not found in strings.xml"
+ value.text
+end
+
+def version()
+ strings :version_name
+end
+
+def app_name()
+ strings :app_name
+end
+
+def main_activity()
+ manifest.root.elements['application'].elements["activity[@android:label='@string/app_name']"].attribute('android:name')
+end
+
+def device_path_exists?(path)
+ path_output =`adb shell ls #{path}`
+ result = path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
+ result
+end
+
+def package_installed? test = false
+ package_name = "#{package}#{'.tests' if test}"
+ ['', '-0', '-1', '-2'].each do |i|
+ path = "/data/app/#{package_name}#{i}.apk"
+ o = `adb shell ls -l #{path}`.chomp
+ if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(path)}$/
+ apk_file = test ? TEST_APK_FILE : APK_FILE
+ if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
+ return true
+ else
+ return false
+ end
+ end
+ end
+ return nil
+end
+
+def replace_faulty_code(faulty_file, faulty_code)
+ explicit_requires = Dir["#{faulty_file.chomp('.rb')}/*.rb"].sort.map { |f| File.basename(f) }.map do |filename|
+ "require 'active_model/validations/#{filename}'"
+ end.join("\n")
+
+ old_code = File.read(faulty_file)
+ new_code = old_code.gsub faulty_code, explicit_requires
+ if new_code != old_code
+ puts "Replaced directory listing code in file #{faulty_file} with explicit requires."
+ File.open(faulty_file, 'w') { |f| f << new_code }
+ else
+ puts "Could not find expected faulty code\n\n#{faulty_code}\n\nin file #{faulty_file}\n\n#{old_code}\n\n"
+ end
+end
+
+def build_apk(t, release)
+ apk_file = release ? RELEASE_APK_FILE : APK_FILE
+ if File.exist?(apk_file)
+ changed_prereqs = t.prerequisites.select do |p|
+ File.file?(p) && !Dir[p].empty? && Dir[p].map { |f| File.mtime(f) }.max > File.mtime(APK_FILE)
+ end
+ return false if changed_prereqs.empty?
+ changed_prereqs.each { |f| puts "#{f} changed." }
+ puts "Forcing rebuild of #{apk_file}."
+ end
+ if release
+ sh 'ant release'
+ else
+ sh 'ant debug'
+ end
+ return true
+end
+
+def install_apk
+ failure_pattern = /^Failure \[(.*)\]/
+ success_pattern = /^Success/
+ case package_installed?
+ when true
+ puts "Package #{package} already installed."
+ return
+ when false
+ puts "Package #{package} already installed, but of different size. Replacing package."
+ output = `adb install -r #{APK_FILE} 2>&1`
+ return if $? == 0 && output !~ failure_pattern && output =~ success_pattern
+ case $1
+ when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
+ puts "Found package signed with different certificate. Uninstalling it and retrying install."
+ else
+ puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
+ puts "Uninstalling #{package} and retrying install."
+ end
+ uninstall_apk
+ end
+ output = `adb install #{APK_FILE} 2>&1`
+ raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
+ clear_update
+end
+
+def uninstall_apk
+ return if package_installed?.nil?
+ puts "Uninstalling package #{package}"
+ system "adb uninstall #{package}"
+ if $? != 0 && package_installed?
+ puts "Uninstall failed exit code #{$?}"
+ exit $?
+ end
+end
+
+def update_scripts
+ `adb shell mkdir -p #{scripts_path}` if !device_path_exists?(scripts_path)
+ puts "Pushing files to apk public file area."
+ last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
+ Dir.chdir('src') do
+ Dir["**/*.rb"].each do |script_file|
+ next if File.directory? script_file
+ next if File.mtime(script_file) < last_update
+ next if script_file =~ /~$/
+ print "#{script_file}: "; $stdout.flush
+ `adb push #{script_file} #{scripts_path}/#{script_file}`
+ end
+ end
+ mark_update
+end
+
+def start_app
+ `adb shell am start -a android.intent.action.MAIN -n #{package}/.#{main_activity}`
+end
+
+def stop_app
+ output = `adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
+ return output !~ /Operation not permitted/
+end
View
44 src/org/ruboto/EntryPointActivity.java
@@ -1,10 +1,5 @@
package org.ruboto;
-import java.io.File;
-import java.io.IOException;
-
-import org.ruboto.Script;
-
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -14,8 +9,6 @@
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
@@ -28,40 +21,40 @@
protected boolean appStarted = false;
public void onCreate(Bundle bundle) {
- Log.d("RUBOTO", "onCreate: ");
+ Log.d("onCreate: ");
try {
splash = Class.forName(getPackageName() + ".R$layout").getField("splash").getInt(null);
} catch (Exception e) {
splash = -1;
}
- if (Script.isInitialized()) {
+ if (JRubyAdapter.isInitialized()) {
appStarted = true;
}
super.onCreate(bundle);
}
public void onResume() {
- Log.d("RUBOTO", "onResume: ");
+ Log.d("onResume: ");
if(appStarted) {
- Log.d("RUBOTO", "onResume: App already started!");
+ Log.d("onResume: App already started!");
super.onResume();
return;
}
- Log.d("RUBOTO", "onResume: Checking JRuby");
- if (Script.isInitialized()) {
- Log.d("RUBOTO", "Already initialized");
+ Log.d("onResume: Checking JRuby");
+ if (JRubyAdapter.isInitialized()) {
+ Log.d("Already initialized");
fireRubotoActivity();
} else {
- Log.d("RUBOTO", "Not initialized");
+ Log.d("Not initialized");
showProgress();
receiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent) {
- Log.i("RUBOTO", "received broadcast: " + intent);
- Log.i("RUBOTO", "URI: " + intent.getData());
+ Log.i("received broadcast: " + intent);
+ Log.i("URI: " + intent.getData());
if (intent.getData().toString().equals("package:org.ruboto.core")) {
Toast.makeText(context,"Ruboto Core is now installed.",Toast.LENGTH_SHORT).show();
if (receiver != null) {
@@ -82,7 +75,7 @@ public void onReceive(Context context, Intent intent) {
}
public void onPause() {
- Log.d("RUBOTO", "onPause: ");
+ Log.d("onPause: ");
if (receiver != null) {
unregisterReceiver(receiver);
@@ -92,7 +85,7 @@ public void onPause() {
}
public void onDestroy() {
- Log.d("RUBOTO", "onDestroy: ");
+ Log.d("onDestroy: ");
super.onDestroy();
if (dialogCancelled) {
@@ -104,9 +97,9 @@ public void onDestroy() {
private void initJRuby(final boolean firstTime) {
new Thread(new Runnable() {
public void run() {
- final boolean jrubyOk = Script.setUpJRuby(EntryPointActivity.this);
+ final boolean jrubyOk = JRubyAdapter.setUpJRuby(EntryPointActivity.this);
if (jrubyOk) {
- Log.d("RUBOTO", "onResume: JRuby OK");
+ Log.d("onResume: JRuby OK");
prepareJRuby();
runOnUiThread(new Runnable() {
public void run() {
@@ -117,7 +110,7 @@ public void run() {
runOnUiThread(new Runnable() {
public void run() {
if (firstTime) {
- Log.d("RUBOTO", "onResume: Checking JRuby - IN UI thread");
+ Log.d("onResume: Checking JRuby - IN UI thread");
try {
setContentView(Class.forName(getPackageName() + ".R$layout").getField("get_ruboto_core").getInt(null));
} catch (Exception e) {
@@ -147,7 +140,6 @@ public void getRubotoCore(View view) {
startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("market://details?id=org.ruboto.core")));
} catch (android.content.ActivityNotFoundException anfe) {
try {
- TextView textView = (TextView) findViewById(Class.forName(getPackageName() + ".R$id").getField("text").getInt(null));
Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(RUBOTO_URL));
startActivity(intent);
} catch (Exception e) {}
@@ -157,7 +149,7 @@ public void getRubotoCore(View view) {
protected void fireRubotoActivity() {
if(appStarted) return;
appStarted = true;
- Log.i("RUBOTO", "Starting activity");
+ Log.i("Starting activity");
loadScript();
onStart();
super.onResume();
@@ -166,7 +158,7 @@ protected void fireRubotoActivity() {
private void showProgress() {
if (loadingDialog == null) {
- Log.i("RUBOTO", "Showing progress");
+ Log.i("Showing progress");
if (splash > 0) {
requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
setContentView(splash);
@@ -185,7 +177,7 @@ public void onCancel(DialogInterface dialog) {
private void hideProgress() {
if (loadingDialog != null) {
- Log.d("RUBOTO", "Hide progress");
+ Log.d("Hide progress");
loadingDialog.dismiss();
loadingDialog = null;
}
View
476 src/org/ruboto/JRubyAdapter.java
@@ -0,0 +1,476 @@
+package org.ruboto;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Environment;
+import dalvik.system.PathClassLoader;
+
+public class JRubyAdapter {
+ private static Object ruby;
+ private static boolean isDebugBuild = false;
+ private static PrintStream output = null;
+ private static boolean initialized = false;
+
+ private static String localContextScope = "SINGLETON";
+ private static String localVariableBehavior = "TRANSIENT";
+
+ private static String RUBOTO_CORE_VERSION_NAME;
+
+ /*************************************************************************************************
+ *
+ * Static Methods: ScriptingContainer config
+ */
+
+ public static void setLocalContextScope(String val) {
+ localContextScope = val;
+ }
+
+ public static void setLocalVariableBehavior(String val) {
+ localVariableBehavior = val;
+ }
+
+ /*************************************************************************************************
+ *
+ * Static Methods: JRuby Execution
+ */
+
+ public static final FilenameFilter RUBY_FILES = new FilenameFilter() {
+ public boolean accept(File dir, String fname) {
+ return fname.endsWith(".rb");
+ }
+ };
+
+ public static synchronized boolean isInitialized() {
+ return initialized;
+ }
+
+ public static boolean usesPlatformApk() {
+ return RUBOTO_CORE_VERSION_NAME != null;
+ }
+
+ public static String getPlatformVersionName() {
+ return RUBOTO_CORE_VERSION_NAME;
+ }
+
+ public static synchronized boolean setUpJRuby(Context appContext) {
+ return setUpJRuby(appContext, output == null ? System.out : output);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static synchronized boolean setUpJRuby(Context appContext, PrintStream out) {
+ if (!initialized) {
+ // BEGIN Ruboto HeapAlloc
+ @SuppressWarnings("unused")
+ byte[] arrayForHeapAllocation = new byte[13 * 1024 * 1024];
+ arrayForHeapAllocation = null;
+ // END Ruboto HeapAlloc
+ setDebugBuild(appContext);
+ Log.d("Setting up JRuby runtime (" + (isDebugBuild ? "DEBUG" : "RELEASE") + ")");
+ System.setProperty("jruby.bytecode.version", "1.6");
+ System.setProperty("jruby.interfaces.useProxy", "true");
+ System.setProperty("jruby.management.enabled", "false");
+ System.setProperty("jruby.objectspace.enabled", "false");
+ System.setProperty("jruby.thread.pooling", "true");
+ System.setProperty("jruby.native.enabled", "false");
+ // System.setProperty("jruby.compat.version", "RUBY1_8"); // RUBY1_9 is the default
+
+ // Uncomment these to debug Ruby source loading
+ // System.setProperty("jruby.debug.loadService", "true");
+ // System.setProperty("jruby.debug.loadService.timing", "true");
+
+
+ ClassLoader classLoader;
+ Class<?> scriptingContainerClass;
+ String apkName = null;
+
+ try {
+ scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer");
+ System.out.println("Found JRuby in this APK");
+ classLoader = JRubyAdapter.class.getClassLoader();
+ try {
+ apkName = appContext.getPackageManager().getApplicationInfo(appContext.getPackageName(), 0).sourceDir;
+ } catch (NameNotFoundException e) {}
+ } catch (ClassNotFoundException e1) {
+ String packageName = "org.ruboto.core";
+ try {
+ PackageInfo pkgInfo = appContext.getPackageManager().getPackageInfo(packageName, 0);
+ apkName = pkgInfo.applicationInfo.sourceDir;
+ RUBOTO_CORE_VERSION_NAME = pkgInfo.versionName;
+ } catch (PackageManager.NameNotFoundException e2) {
+ out.println("JRuby not found in local APK:");
+ e1.printStackTrace(out);
+ out.println("JRuby not found in platform APK:");
+ e2.printStackTrace(out);
+ return false;
+ }
+
+ System.out.println("Found JRuby in platform APK");
+ classLoader = new PathClassLoader(apkName, JRubyAdapter.class.getClassLoader());
+
+ try {
+ scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, classLoader);
+ } catch (ClassNotFoundException e) {
+ // FIXME(uwe): ScriptingContainer not found in the platform APK...
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ try {
+ Class scopeClass = Class.forName("org.jruby.embed.LocalContextScope", true, scriptingContainerClass.getClassLoader());
+ Class behaviorClass = Class.forName("org.jruby.embed.LocalVariableBehavior", true, scriptingContainerClass.getClassLoader());
+
+ ruby = scriptingContainerClass
+ .getConstructor(scopeClass, behaviorClass)
+ .newInstance(Enum.valueOf(scopeClass, localContextScope),
+ Enum.valueOf(behaviorClass, localVariableBehavior));
+
+ Class compileModeClass = Class.forName("org.jruby.RubyInstanceConfig$CompileMode", true, classLoader);
+ callScriptingContainerMethod(Void.class, "setCompileMode", Enum.valueOf(compileModeClass, "OFF"));
+
+ // Class traceTypeClass = Class.forName("org.jruby.runtime.backtrace.TraceType", true, classLoader);
+ // Method traceTypeForMethod = traceTypeClass.getMethod("traceTypeFor", String.class);
+ // Object traceTypeRaw = traceTypeForMethod.invoke(null, "raw");
+ // callScriptingContainerMethod(Void.class, "setTraceType", traceTypeRaw);
+
+ // FIXME(uwe): Write tutorial on profiling.
+ // container.getProvider().getRubyInstanceConfig().setProfilingMode(mode);
+
+ // callScriptingContainerMethod(Void.class, "setClassLoader", classLoader);
+ Method setClassLoaderMethod = ruby.getClass().getMethod("setClassLoader", ClassLoader.class);
+ setClassLoaderMethod.invoke(ruby, classLoader);
+
+ Thread.currentThread().setContextClassLoader(classLoader);
+
+ String defaultCurrentDir = appContext.getFilesDir().getPath();
+ Log.d("Setting JRuby current directory to " + defaultCurrentDir);
+ callScriptingContainerMethod(Void.class, "setCurrentDirectory", defaultCurrentDir);
+
+ if (out != null) {
+ output = out;
+ setOutputStream(out);
+ } else if (output != null) {
+ setOutputStream(output);
+ }
+
+ String jrubyHome = "file:" + apkName + "!";
+ Log.i("Setting JRUBY_HOME: " + jrubyHome);
+ System.setProperty("jruby.home", jrubyHome);
+
+ String extraScriptsDir = scriptsDirName(appContext);
+ Log.i("Checking scripts in " + extraScriptsDir);
+ if (configDir(extraScriptsDir)) {
+ Log.i("Added extra scripts path: " + extraScriptsDir);
+ }
+ initialized = true;
+ } catch (ClassNotFoundException e) {
+ handleInitException(e);
+ } catch (IllegalArgumentException e) {
+ handleInitException(e);
+ } catch (SecurityException e) {
+ handleInitException(e);
+ } catch (InstantiationException e) {
+ handleInitException(e);
+ } catch (IllegalAccessException e) {
+ handleInitException(e);
+ } catch (InvocationTargetException e) {
+ handleInitException(e);
+ } catch (NoSuchMethodException e) {
+ handleInitException(e);
+ }
+ }
+ return initialized;
+ }
+
+ private static String scriptsDirName(Context context) {
+ File storageDir = null;
+ if (JRubyAdapter.isDebugBuild()) {
+
+ // FIXME(uwe): Simplify this as soon as we drop support for android-7
+ if (android.os.Build.VERSION.SDK_INT >= 8) {
+ try {
+ Method method = context.getClass().getMethod("getExternalFilesDir", String.class);
+ storageDir = (File) method.invoke(context, (Object) null);
+ } catch (SecurityException e) {
+ printStackTrace(e);
+ } catch (NoSuchMethodException e) {
+ printStackTrace(e);
+ } catch (IllegalArgumentException e) {
+ printStackTrace(e);
+ } catch (IllegalAccessException e) {
+ printStackTrace(e);
+ } catch (InvocationTargetException e) {
+ printStackTrace(e);
+ }
+ } else {
+ storageDir = new File(Environment.getExternalStorageDirectory(), "Android/data/" + context.getPackageName() + "/files");
+ Log.e("Calculated path to sdcard the old way: " + storageDir);
+ }
+ // FIXME end
+
+ if (storageDir == null || (!storageDir.exists() && !storageDir.mkdirs())) {
+ Log.e("Development mode active, but sdcard is not available. Make sure you have added\n<uses-permission android:name='android.permission.WRITE_EXTERNAL_STORAGE' />\nto your AndroidManifest.xml file.");
+ storageDir = context.getFilesDir();
+ }
+ } else {
+ storageDir = context.getFilesDir();
+ }
+ return storageDir.getAbsolutePath() + "/scripts";
+ }
+
+ public static Boolean configDir(String scriptsDir) {
+ if (new File(scriptsDir).exists()) {
+ Log.i("Found extra scripts dir: " + scriptsDir);
+ Script.setDir(scriptsDir);
+ JRubyAdapter.exec("$:.unshift '" + scriptsDir + "' ; $:.uniq!");
+ return true;
+ } else {
+ Log.i("Extra scripts dir not present: " + scriptsDir);
+ return false;
+ }
+ }
+
+ public static void setOutputStream(PrintStream out) {
+ if (ruby == null) {
+ output = out;
+ } else {
+ try {
+ Method setOutputMethod = ruby.getClass().getMethod("setOutput", PrintStream.class);
+ setOutputMethod.invoke(ruby, out);
+ Method setErrorMethod = ruby.getClass().getMethod("setError", PrintStream.class);
+ setErrorMethod.invoke(ruby, out);
+ } catch (IllegalArgumentException e) {
+ handleInitException(e);
+ } catch (SecurityException e) {
+ handleInitException(e);
+ } catch (IllegalAccessException e) {
+ handleInitException(e);
+ } catch (InvocationTargetException e) {
+ handleInitException(e);
+ } catch (NoSuchMethodException e) {
+ handleInitException(e);
+ }
+ }
+ }
+
+ private static void handleInitException(Exception e) {
+ Log.e("Exception starting JRuby");
+ Log.e(e.getMessage() != null ? e.getMessage() : e.getClass().getName());
+ e.printStackTrace();
+ ruby = null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T callScriptingContainerMethod(Class<T> returnType, String methodName, Object... args) {
+ Class<?>[] argClasses = new Class[args.length];
+ for (int i = 0; i < argClasses.length; i++) {
+ argClasses[i] = args[i].getClass();
+ }
+ try {
+ Method method = ruby.getClass().getMethod(methodName, argClasses);
+ System.out.println("callScriptingContainerMethod: method: " + method);
+ T result = (T) method.invoke(ruby, args);
+ System.out.println("callScriptingContainerMethod: result: " + result);
+ return result;
+ } catch (RuntimeException re) {
+ re.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ printStackTrace(e);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static String execute(String code) {
+ Object result = exec(code);
+ return result != null ? result.toString() : "nil";
+// TODO: Why is callMethod returning "main"?
+// return result != null ? callMethod(result, "inspect", String.class) : "null";
+ }
+
+ public static Object exec(String code) {
+ // return callScriptingContainerMethod(Object.class, "runScriptlet", code);
+ try {
+ Method runScriptletMethod = ruby.getClass().getMethod("runScriptlet", String.class);
+ return runScriptletMethod.invoke(ruby, code);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ } catch (IllegalAccessException iae) {
+ throw new RuntimeException(iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ if (isDebugBuild) {
+ throw ((RuntimeException) ite.getCause());
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public static void defineGlobalConstant(String name, Object object) {
+ put(name, object);
+ }
+
+ public static void put(String name, Object object) {
+ try {
+ Method putMethod = ruby.getClass().getMethod("put", String.class, Object.class);
+ putMethod.invoke(ruby, name, object);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ } catch (IllegalAccessException iae) {
+ throw new RuntimeException(iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ throw new RuntimeException(ite);
+ }
+ }
+
+ public static Object get(String name) {
+ try {
+ Method getMethod = ruby.getClass().getMethod("get", String.class);
+ return getMethod.invoke(ruby, name);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ } catch (IllegalAccessException iae) {
+ throw new RuntimeException(iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ throw new RuntimeException(ite);
+ }
+ }
+
+ public static void defineGlobalVariable(String name, Object object) {
+ defineGlobalConstant(name, object);
+ }
+
+ public static boolean isDebugBuild() {
+ return isDebugBuild;
+ }
+
+ private static void setDebugBuild(Context context) {
+ PackageManager pm = context.getPackageManager();
+ PackageInfo pi;
+ try {
+ pi = pm.getPackageInfo(context.getPackageName(), 0);
+ isDebugBuild = ((pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+ } catch (NameNotFoundException e) {
+ isDebugBuild = false;
+ }
+ }
+
+ /*************************************************************************************************
+ *
+ * Script Actions
+ */
+
+ public static String getScriptFilename() {
+ return callScriptingContainerMethod(String.class, "getScriptFilename");
+ }
+
+ public static void setScriptFilename(String name) {
+ callScriptingContainerMethod(Void.class, "setScriptFilename", name);
+ }
+
+ public static void callMethod(Object receiver, String methodName, Object[] args) {
+ try {
+ Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Object[].class);
+ callMethodMethod.invoke(ruby, receiver, methodName, args);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ } catch (IllegalAccessException iae) {
+ throw new RuntimeException(iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ printStackTrace(ite);
+ if (isDebugBuild) {
+ throw new RuntimeException(ite);
+ }
+ }
+ }
+
+ public static void callMethod(Object object, String methodName, Object arg) {
+ callMethod(object, methodName, new Object[] { arg });
+ }
+
+ public static void callMethod(Object object, String methodName) {
+ callMethod(object, methodName, new Object[] {});
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T callMethod(Object receiver, String methodName, Object[] args, Class<T> returnType) {
+ try {
+ Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Object[].class, Class.class);
+ return (T) callMethodMethod.invoke(ruby, receiver, methodName, args, returnType);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ } catch (IllegalAccessException iae) {
+ throw new RuntimeException(iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ printStackTrace(ite);
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T callMethod(Object receiver, String methodName, Object arg, Class<T> returnType) {
+ try {
+ Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Object.class, Class.class);
+ return (T) callMethodMethod.invoke(ruby, receiver, methodName, arg, returnType);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ } catch (IllegalAccessException iae) {
+ throw new RuntimeException(iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ printStackTrace(ite);
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T callMethod(Object receiver, String methodName, Class<T> returnType) {
+ try {
+ Method callMethodMethod = ruby.getClass().getMethod("callMethod", Object.class, String.class, Class.class);
+ return (T) callMethodMethod.invoke(ruby, receiver, methodName, returnType);
+ } catch (NoSuchMethodException nsme) {
+ throw new RuntimeException(nsme);
+ } catch (IllegalAccessException iae) {
+ throw new RuntimeException(iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ printStackTrace(ite);
+ }
+ return null;
+ }
+
+ private static void printStackTrace(Throwable t) {
+ PrintStream out;
+ try {
+ Method getOutputMethod = ruby.getClass().getMethod("getOutput");
+ out = (PrintStream) getOutputMethod.invoke(ruby);
+ } catch (java.lang.NoSuchMethodException nsme) {
+ throw new RuntimeException("ScriptingContainer#getOutput method not found.", nsme);
+ } catch (java.lang.IllegalAccessException iae) {
+ throw new RuntimeException("ScriptingContainer#getOutput method not accessable.", iae);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ throw new RuntimeException("ScriptingContainer#getOutput failed.", ite);
+ }
+
+ // TODO(uwe): Simplify this when Issue #144 is resolved
+ try {
+ t.printStackTrace(out);
+ } catch (NullPointerException npe) {
+ // TODO(uwe): printStackTrace should not fail
+ for (java.lang.StackTraceElement ste : t.getStackTrace()) {
+ out.append(ste.toString() + "\n");
+ }
+ }
+ }
+
+}
View
22 src/org/ruboto/Log.java
@@ -0,0 +1,22 @@
+package org.ruboto;
+
+public class Log {
+ public static final String TAG = "RUBOTO";
+
+ public static void d(String message) {
+ android.util.Log.d(TAG, message);
+ }
+
+ public static void i(String message) {
+ android.util.Log.i(TAG, message);
+ }
+
+ public static void e(String message) {
+ android.util.Log.e(TAG, message);
+ }
+
+ public static void e(String message, Throwable t) {
+ android.util.Log.e(TAG, message, t);
+ }
+
+}
View
857 src/org/ruboto/RubotoActivity.java
@@ -5,19 +5,14 @@
import org.ruboto.Script;
import android.app.ProgressDialog;
-import android.content.Intent;
-import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
public class RubotoActivity extends android.app.Activity {
private String scriptName;
private String remoteVariable = null;
private Object[] args;
private Bundle configBundle = null;
+ private Object rubyInstance;
public static final int CB_ACTIVITY_RESULT = 0;
public static final int CB_CHILD_TITLE_CHANGED = 1;
@@ -51,22 +46,22 @@
public static final int CB_RESTART = 29;
public static final int CB_RESTORE_INSTANCE_STATE = 30;
public static final int CB_RESUME = 31;
- public static final int CB_RETAIN_NON_CONFIGURATION_INSTANCE = 32;
- public static final int CB_SAVE_INSTANCE_STATE = 33;
- public static final int CB_SEARCH_REQUESTED = 34;
- public static final int CB_START = 35;
- public static final int CB_STOP = 36;
- public static final int CB_TITLE_CHANGED = 37;
- public static final int CB_TOUCH_EVENT = 38;
- public static final int CB_TRACKBALL_EVENT = 39;
- public static final int CB_WINDOW_ATTRIBUTES_CHANGED = 40;
- public static final int CB_WINDOW_FOCUS_CHANGED = 41;
- public static final int CB_USER_INTERACTION = 42;
- public static final int CB_USER_LEAVE_HINT = 43;
- public static final int CB_ATTACHED_TO_WINDOW = 44;
- public static final int CB_BACK_PRESSED = 45;
- public static final int CB_DETACHED_FROM_WINDOW = 46;
- public static final int CB_KEY_LONG_PRESS = 47;
+ public static final int CB_SAVE_INSTANCE_STATE = 32;
+ public static final int CB_SEARCH_REQUESTED = 33;
+ public static final int CB_START = 34;
+ public static final int CB_STOP = 35;
+ public static final int CB_TITLE_CHANGED = 36;
+ public static final int CB_TOUCH_EVENT = 37;
+ public static final int CB_TRACKBALL_EVENT = 38;
+ public static final int CB_WINDOW_ATTRIBUTES_CHANGED = 39;
+ public static final int CB_WINDOW_FOCUS_CHANGED = 40;
+ public static final int CB_USER_INTERACTION = 41;
+ public static final int CB_USER_LEAVE_HINT = 42;
+ public static final int CB_ATTACHED_TO_WINDOW = 43;
+ public static final int CB_BACK_PRESSED = 44;
+ public static final int CB_DETACHED_FROM_WINDOW = 45;
+ public static final int CB_KEY_LONG_PRESS = 46;
+ public static final int CB_APPLY_THEME_RESOURCE = 47;
private Object[] callbackProcs = new Object[48];
@@ -114,31 +109,45 @@ public void onCreate(Bundle bundle) {
super.onCreate(bundle);
- if (Script.isInitialized()) {
+ if (JRubyAdapter.isInitialized()) {
prepareJRuby();
loadScript();
}
}
- // This causes JRuby to initialize and takes while
+ // TODO(uwe): Only needed for non-class-based definitions
+ // Can be removed if we stop supporting non-class-based definitions
+ // This causes JRuby to initialize and takes a while.
protected void prepareJRuby() {
- Script.put("$context", this);
- Script.put("$activity", this);
- Script.put("$bundle", args[0]);
+ JRubyAdapter.put("$context", this);
+ JRubyAdapter.put("$activity", this);
+ JRubyAdapter.put("$bundle", args[0]);
}
+ // TODO end
protected void loadScript() {
try {
if (scriptName != null) {
- Script.setScriptFilename(getClass().getClassLoader().getResource(scriptName).getPath());
- Script.execute(new Script(scriptName).getContents());
+ String rubyClassName = Script.toCamelCase(scriptName);
+ System.out.println("Looking for Ruby class: " + rubyClassName);
+ Object rubyClass = JRubyAdapter.get(rubyClassName);
+ if (rubyClass == null) {
+ System.out.println("Loading script: " + scriptName);
+ JRubyAdapter.exec(new Script(scriptName).getContents());
+ rubyClass = JRubyAdapter.get(rubyClassName);
+ }
+ if (rubyClass != null) {
+ System.out.println("Instanciating Ruby class: " + rubyClassName);
+ rubyInstance = JRubyAdapter.callMethod(rubyClass, "new", this, Object.class);
+ JRubyAdapter.callMethod(rubyInstance, "on_create", args[0]);
+ }
} else if (configBundle != null) {
- // TODO: Why doesn't this work?
- // Script.callMethod(this, "initialize_ruboto");
- Script.execute("$activity.initialize_ruboto");
// TODO: Why doesn't this work?
- // Script.callMethod(this, "on_create", args[0]);
- Script.execute("$activity.on_create($bundle)");
+ // JRubyAdapter.callMethod(this, "initialize_ruboto");
+ JRubyAdapter.execute("$activity.initialize_ruboto");
+ // TODO: Why doesn't this work?
+ // JRubyAdapter.callMethod(this, "on_create", args[0]);
+ JRubyAdapter.execute("$activity.on_create($bundle)");
}
} catch(IOException e){
e.printStackTrace();
@@ -156,434 +165,914 @@ public boolean rubotoAttachable() {
*/
public void onActivityResult(int requestCode, int resultCode, android.content.Intent data) {
- if (callbackProcs[CB_ACTIVITY_RESULT] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_activity_result"}, Boolean.class)) {
super.onActivityResult(requestCode, resultCode, data);
- Script.callMethod(callbackProcs[CB_ACTIVITY_RESULT], "call" , new Object[]{requestCode, resultCode, data});
+ JRubyAdapter.callMethod(rubyInstance, "on_activity_result" , new Object[]{requestCode, resultCode, data});
} else {
- super.onActivityResult(requestCode, resultCode, data);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onActivityResult"}, Boolean.class)) {
+ super.onActivityResult(requestCode, resultCode, data);
+ JRubyAdapter.callMethod(rubyInstance, "onActivityResult" , new Object[]{requestCode, resultCode, data});
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_ACTIVITY_RESULT] != null) {
+ super.onActivityResult(requestCode, resultCode, data);
+ JRubyAdapter.callMethod(callbackProcs[CB_ACTIVITY_RESULT], "call" , new Object[]{requestCode, resultCode, data});
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
}
}
public void onChildTitleChanged(android.app.Activity childActivity, java.lang.CharSequence title) {
- if (callbackProcs[CB_CHILD_TITLE_CHANGED] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_child_title_changed"}, Boolean.class)) {
super.onChildTitleChanged(childActivity, title);
- Script.callMethod(callbackProcs[CB_CHILD_TITLE_CHANGED], "call" , new Object[]{childActivity, title});
+ JRubyAdapter.callMethod(rubyInstance, "on_child_title_changed" , new Object[]{childActivity, title});
} else {
- super.onChildTitleChanged(childActivity, title);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onChildTitleChanged"}, Boolean.class)) {
+ super.onChildTitleChanged(childActivity, title);
+ JRubyAdapter.callMethod(rubyInstance, "onChildTitleChanged" , new Object[]{childActivity, title});
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CHILD_TITLE_CHANGED] != null) {
+ super.onChildTitleChanged(childActivity, title);
+ JRubyAdapter.callMethod(callbackProcs[CB_CHILD_TITLE_CHANGED], "call" , new Object[]{childActivity, title});
+ } else {
+ super.onChildTitleChanged(childActivity, title);
+ }
+ }
}
}
public void onConfigurationChanged(android.content.res.Configuration newConfig) {
- if (callbackProcs[CB_CONFIGURATION_CHANGED] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_configuration_changed"}, Boolean.class)) {
super.onConfigurationChanged(newConfig);
- Script.callMethod(callbackProcs[CB_CONFIGURATION_CHANGED], "call" , newConfig);
+ JRubyAdapter.callMethod(rubyInstance, "on_configuration_changed" , newConfig);
} else {
- super.onConfigurationChanged(newConfig);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onConfigurationChanged"}, Boolean.class)) {
+ super.onConfigurationChanged(newConfig);
+ JRubyAdapter.callMethod(rubyInstance, "onConfigurationChanged" , newConfig);
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CONFIGURATION_CHANGED] != null) {
+ super.onConfigurationChanged(newConfig);
+ JRubyAdapter.callMethod(callbackProcs[CB_CONFIGURATION_CHANGED], "call" , newConfig);
+ } else {
+ super.onConfigurationChanged(newConfig);
+ }
+ }
}
}
public void onContentChanged() {
- if (callbackProcs[CB_CONTENT_CHANGED] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_content_changed"}, Boolean.class)) {
super.onContentChanged();
- Script.callMethod(callbackProcs[CB_CONTENT_CHANGED], "call" );
+ JRubyAdapter.callMethod(rubyInstance, "on_content_changed" );
} else {
- super.onContentChanged();
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onContentChanged"}, Boolean.class)) {
+ super.onContentChanged();
+ JRubyAdapter.callMethod(rubyInstance, "onContentChanged" );
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CONTENT_CHANGED] != null) {
+ super.onContentChanged();
+ JRubyAdapter.callMethod(callbackProcs[CB_CONTENT_CHANGED], "call" );
+ } else {
+ super.onContentChanged();
+ }
+ }
}
}
public boolean onContextItemSelected(android.view.MenuItem item) {
- if (callbackProcs[CB_CONTEXT_ITEM_SELECTED] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_context_item_selected"}, Boolean.class)) {
super.onContextItemSelected(item);
- return (Boolean) Script.callMethod(callbackProcs[CB_CONTEXT_ITEM_SELECTED], "call" , item, Boolean.class);
+ return (Boolean) JRubyAdapter.callMethod(rubyInstance, "on_context_item_selected" , item, Boolean.class);
} else {
- return super.onContextItemSelected(item);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onContextItemSelected"}, Boolean.class)) {
+ super.onContextItemSelected(item);
+ return (Boolean) JRubyAdapter.callMethod(rubyInstance, "onContextItemSelected" , item, Boolean.class);
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CONTEXT_ITEM_SELECTED] != null) {
+ super.onContextItemSelected(item);
+ return (Boolean) JRubyAdapter.callMethod(callbackProcs[CB_CONTEXT_ITEM_SELECTED], "call" , item, Boolean.class);
+ } else {
+ return super.onContextItemSelected(item);
+ }
+ }
}
}
public void onContextMenuClosed(android.view.Menu menu) {
- if (callbackProcs[CB_CONTEXT_MENU_CLOSED] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_context_menu_closed"}, Boolean.class)) {
super.onContextMenuClosed(menu);
- Script.callMethod(callbackProcs[CB_CONTEXT_MENU_CLOSED], "call" , menu);
+ JRubyAdapter.callMethod(rubyInstance, "on_context_menu_closed" , menu);
} else {
- super.onContextMenuClosed(menu);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onContextMenuClosed"}, Boolean.class)) {
+ super.onContextMenuClosed(menu);
+ JRubyAdapter.callMethod(rubyInstance, "onContextMenuClosed" , menu);
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CONTEXT_MENU_CLOSED] != null) {
+ super.onContextMenuClosed(menu);
+ JRubyAdapter.callMethod(callbackProcs[CB_CONTEXT_MENU_CLOSED], "call" , menu);
+ } else {
+ super.onContextMenuClosed(menu);
+ }
+ }
}
}
public void onCreateContextMenu(android.view.ContextMenu menu, android.view.View v, android.view.ContextMenu.ContextMenuInfo menuInfo) {
- if (callbackProcs[CB_CREATE_CONTEXT_MENU] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_create_context_menu"}, Boolean.class)) {
super.onCreateContextMenu(menu, v, menuInfo);
- Script.callMethod(callbackProcs[CB_CREATE_CONTEXT_MENU], "call" , new Object[]{menu, v, menuInfo});
+ JRubyAdapter.callMethod(rubyInstance, "on_create_context_menu" , new Object[]{menu, v, menuInfo});
} else {
- super.onCreateContextMenu(menu, v, menuInfo);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onCreateContextMenu"}, Boolean.class)) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ JRubyAdapter.callMethod(rubyInstance, "onCreateContextMenu" , new Object[]{menu, v, menuInfo});
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CREATE_CONTEXT_MENU] != null) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ JRubyAdapter.callMethod(callbackProcs[CB_CREATE_CONTEXT_MENU], "call" , new Object[]{menu, v, menuInfo});
+ } else {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ }
+ }
}
}
public java.lang.CharSequence onCreateDescription() {
- if (callbackProcs[CB_CREATE_DESCRIPTION] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_create_description"}, Boolean.class)) {
super.onCreateDescription();
- return (java.lang.CharSequence) Script.callMethod(callbackProcs[CB_CREATE_DESCRIPTION], "call" , java.lang.CharSequence.class);
+ return (java.lang.CharSequence) JRubyAdapter.callMethod(rubyInstance, "on_create_description" , java.lang.CharSequence.class);
} else {
- return super.onCreateDescription();
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onCreateDescription"}, Boolean.class)) {
+ super.onCreateDescription();
+ return (java.lang.CharSequence) JRubyAdapter.callMethod(rubyInstance, "onCreateDescription" , java.lang.CharSequence.class);
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CREATE_DESCRIPTION] != null) {
+ super.onCreateDescription();
+ return (java.lang.CharSequence) JRubyAdapter.callMethod(callbackProcs[CB_CREATE_DESCRIPTION], "call" , java.lang.CharSequence.class);
+ } else {
+ return super.onCreateDescription();
+ }
+ }
}
}
public boolean onCreateOptionsMenu(android.view.Menu menu) {
- if (callbackProcs[CB_CREATE_OPTIONS_MENU] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_create_options_menu"}, Boolean.class)) {
super.onCreateOptionsMenu(menu);
- return (Boolean) Script.callMethod(callbackProcs[CB_CREATE_OPTIONS_MENU], "call" , menu, Boolean.class);
+ return (Boolean) JRubyAdapter.callMethod(rubyInstance, "on_create_options_menu" , menu, Boolean.class);
} else {
- return super.onCreateOptionsMenu(menu);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onCreateOptionsMenu"}, Boolean.class)) {
+ super.onCreateOptionsMenu(menu);
+ return (Boolean) JRubyAdapter.callMethod(rubyInstance, "onCreateOptionsMenu" , menu, Boolean.class);
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CREATE_OPTIONS_MENU] != null) {
+ super.onCreateOptionsMenu(menu);
+ return (Boolean) JRubyAdapter.callMethod(callbackProcs[CB_CREATE_OPTIONS_MENU], "call" , menu, Boolean.class);
+ } else {
+ return super.onCreateOptionsMenu(menu);
+ }
+ }
}
}
public boolean onCreatePanelMenu(int featureId, android.view.Menu menu) {
- if (callbackProcs[CB_CREATE_PANEL_MENU] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_create_panel_menu"}, Boolean.class)) {
super.onCreatePanelMenu(featureId, menu);
- return (Boolean) Script.callMethod(callbackProcs[CB_CREATE_PANEL_MENU], "call" , new Object[]{featureId, menu}, Boolean.class);
+ return (Boolean) JRubyAdapter.callMethod(rubyInstance, "on_create_panel_menu" , new Object[]{featureId, menu}, Boolean.class);
} else {
- return super.onCreatePanelMenu(featureId, menu);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onCreatePanelMenu"}, Boolean.class)) {
+ super.onCreatePanelMenu(featureId, menu);
+ return (Boolean) JRubyAdapter.callMethod(rubyInstance, "onCreatePanelMenu" , new Object[]{featureId, menu}, Boolean.class);
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CREATE_PANEL_MENU] != null) {
+ super.onCreatePanelMenu(featureId, menu);
+ return (Boolean) JRubyAdapter.callMethod(callbackProcs[CB_CREATE_PANEL_MENU], "call" , new Object[]{featureId, menu}, Boolean.class);
+ } else {
+ return super.onCreatePanelMenu(featureId, menu);
+ }
+ }
}
}
public android.view.View onCreatePanelView(int featureId) {
- if (callbackProcs[CB_CREATE_PANEL_VIEW] != null) {
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"on_create_panel_view"}, Boolean.class)) {
super.onCreatePanelView(featureId);
- return (android.view.View) Script.callMethod(callbackProcs[CB_CREATE_PANEL_VIEW], "call" , featureId, android.view.View.class);
+ return (android.view.View) JRubyAdapter.callMethod(rubyInstance, "on_create_panel_view" , featureId, android.view.View.class);
} else {
- return super.onCreatePanelView(featureId);
+ if (rubyInstance != null && JRubyAdapter.callMethod(rubyInstance, "respond_to?" , new Object[]{"onCreatePanelView"}, Boolean.class)) {
+ super.onCreatePanelView(featureId);
+ return (android.view.View) JRubyAdapter.callMethod(rubyInstance, "onCreatePanelView" , featureId, android.view.View.class);
+ } else {
+ if (callbackProcs != null && callbackProcs[CB_CREATE_PANEL_VIEW] != null) {
+ super.onCreatePanelView(featureId);
+ return (android.view.View) JRubyAdapter.callMethod(callbackProcs[CB_CREATE_PANEL_VIEW], "call" , featureId, android.view.View.class);
+ } else {
+