Ruboto - JRuby on Android at JRubyConf.eu 2012

Ruboto - JRuby on Android at JRubyConf.eu 2012

4bfcb18ca5298df54d8eb410244d004f?s=128

Uwe Kubosch

August 17, 2012
Tweet

Transcript

  1. None
  2. Ruboto JRuby on Android

  3. Uwe Kubosch Work at Datek Wireless in Norway Ruboto core

    developer JRuby rookie committer
  4. Ruboto? Builds on JRuby and Android Application and component generators

    Compact GUI definition Rake based development Test framework
  5. Topics covered History Ruboto IRB Installation & development tools Hello

    world! SpyCam Limitations Roadmap
  6. Activity: A screen View: A screen component Service: Background process

    Intent: Definition of action BroadcastReceiver: Listener for Intents Android basics/terms
  7. History 2009 PoC by Charles Nutter (headius) february 24, 2009

    ruboto-irb by headius august 1, 2009
  8. History 2009 PoC by Charles Nutter (headius) february 24, 2009

    ruboto-irb by headius august 1, 2009
  9. History 2009 PoC by Charles Nutter (headius) february 24, 2009

    ruboto-irb by headius august 1, 2009
  10. History 2009 PoC by Charles Nutter (headius) february 24, 2009

    ruboto-irb by headius august 1, 2009
  11. History 2009 PoC by Charles Nutter (headius) february 24, 2009

    ruboto-irb by headius august 1, 2009
  12. Demo: OpenGL

  13. History 2010 ruboto-core : GSoC 2010 by Daniel Jackoway Version

    0.0.3 released december 19, 2010
  14. History 2011 Testing framework: Feb 13, 2011 (my first contribution)

    Bundler support: may 21, 2011 New Logo & Icons by RedNifre: july 20, 2011 RubotoCore platform package: august 2011 Rename to just “ruboto”: december 24, 2011
  15. History 2011 Testing framework: Feb 13, 2011 (my first contribution)

    Bundler support: may 21, 2011 New Logo & Icons by RedNifre: july 20, 2011 RubotoCore platform package: august 2011 Rename to just “ruboto”: december 24, 2011
  16. History 2012 On-device generation of subclasses may 10, 2012 Class

    oriented component definition, 2012
  17. History 2012 On-device generation of subclasses may 10, 2012 Class

    oriented component definition, 2012 require  'ruboto/generate' ruboto_generate_widget(android.widget.EditText  =>  "your.package.RubotoEditText") @edit_script  =  ruboto_edit_text(:text  =>  ‘Hello!’) @edit_script.initialize_ruboto_callbacks  do    def  on_draw(canvas)        #  Do  Something    end end
  18. History 2012 On-device generation of subclasses may 10, 2012 Class

    oriented component definition, 2012
  19. History 2012 On-device generation of subclasses may 10, 2012 Class

    oriented component definition, 2012 $activity.handle_create do |bundle| setTitle ‘Hello World!’ setup_content do linear_layout :orientation => LinearLayout::VERTICAL do @text_view = text_view :text => 'What hath Matz wrought?' button :text => ‘Click me!’, :width => :wrap_content, :id => 43 end end handle_click do |view| if view.id == 43 @text_view.setText 'What hath Matz wrought!' toast 'Flipped a bit via butterfly' end end end
  20. History 2012 On-device generation of subclasses may 10, 2012 Class

    oriented component definition, 2012 $activity.handle_create do |bundle| setTitle ‘Hello World!’ setup_content do linear_layout :orientation => LinearLayout::VERTICAL do @text_view = text_view :text => 'What hath Matz wrought?' button :text => ‘Click me!’, :width => :wrap_content, :id => 43 end end handle_click do |view| if view.id == 43 @text_view.setText 'What hath Matz wrought!' toast 'Flipped a bit via butterfly' end end end $activity.start_ruboto_activity do def on_create(bundle) setTitle ‘Hello World!’ click_handler = proc do |view| @text_view.setText 'What hath Matz wrought!' toast 'Flipped a bit via butterfly' end self.content_view = linear_layout :orientation => LinearLayout::VERTICAL do @text_view = text_view :text => 'What hath Matz wrought?' button :text => ‘Click me!, :width => :wrap_content, :on_click_listener => click_handler end end end
  21. History 2012 On-device generation of subclasses may 10, 2012 Class

    oriented component definition, 2012 $activity.handle_create do |bundle| setTitle ‘Hello World!’ setup_content do linear_layout :orientation => LinearLayout::VERTICAL do @text_view = text_view :text => 'What hath Matz wrought?' button :text => ‘Click me!’, :width => :wrap_content, :id => 43 end end handle_click do |view| if view.id == 43 @text_view.setText 'What hath Matz wrought!' toast 'Flipped a bit via butterfly' end end end $activity.start_ruboto_activity do def on_create(bundle) setTitle ‘Hello World!’ click_handler = proc do |view| @text_view.setText 'What hath Matz wrought!' toast 'Flipped a bit via butterfly' end self.content_view = linear_layout :orientation => LinearLayout::VERTICAL do @text_view = text_view :text => 'What hath Matz wrought?' button :text => ‘Click me!, :width => :wrap_content, :on_click_listener => click_handler end end end class ImageButtonActivity def on_create(bundle) set_title ‘Hello World!’ click_handler = proc do |view| @text_view.setText 'What hath Matz wrought!' toast 'Flipped a bit via butterfly' end self.content_view = linear_layout :orientation => :vertical do @text_view = text_view :text => 'What hath Matz wrought?' button :text => ‘Click me!’, :width => :wrap_content, :id => 43, :on_click_listener => click_handler end end end
  22. Installation A Ruby implementation: Ruby 1.8.7, Ruby 1.9.3, JRuby, and

    Rubinius supported. Java JDK Apache ANT Android SDK [sudo] gem install ruboto Put all these in your PATH
  23. Tooling The “ruboto” command Rake

  24. Tooling - create project ruboto gen app --package my.cool.super_app

  25. Tooling - create project The “ruboto” command ruboto gem app

    --package my.cool. Rake based $ ruboto gen app --package my.cool.super_app Generating Android app SuperApp in /Users/uwe/workspace/jruby/super_app... ... Added file super_app/src/my/cool/super_app/SuperAppActivity.java ... Added file super_app/res/values/strings.xml Added file super_app/res/layout/main.xml Added file super_app/AndroidManifest.xml Added file super_app/build.xml Added file super_app/proguard-project.txt Removed file src/my/cool/super_app/SuperAppActivity.java Removed file res/layout/main.xml ... Added file /Users/uwe/workspace/jruby/super_app/src/my/cool/super_app/SuperAppActivity.java. Added file /Users/uwe/workspace/jruby/super_app/src/super_app_activity.rb. Added file /Users/uwe/workspace/jruby/super_app/test/src/super_app_activity_test.rb.
  26. Tooling - create component ruboto gen class Activity --name MyActivity

  27. Tooling - create component ruboto gen class Activity --name MyActivity

    $ ruboto gen class Activity --name MyActivity Added file /Users/uwe/workspace/jruby/hello_world/src/presentation/hello_world/MyActivity.java. Added file /Users/uwe/workspace/jruby/hello_world/src/my_activity.rb. Added file /Users/uwe/workspace/jruby/hello_world/test/src/my_activity_test.rb. Added activity to manifest.
  28. Tooling - build APK rake debug rake release

  29. Tooling - Install and run APK rake install rake start

    rake install start rake update_scripts:restart
  30. Questions?

  31. Hello World!

  32. Hello world!

  33. Hello world! $ android create project --target android-8 --path hello_world

    --package presentation.hello_world --activity HelloWorldActivity Generates file src/presentation/HelloWorldActivity.java
  34. Hello world! $ android create project --target android-8 --path hello_world

    --package presentation.hello_world --activity HelloWorldActiv Generates file src/presentation/HelloWorldActivity.java
  35. Hello world! $ android create project --target android-8 --pat... Generates

    file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  36. Hello world! $ android create project --target android-8 --pat... Generates

    file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:gravity="center_horizontal|center_vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" /> </LinearLayout>
  37. Hello world! $ android create project --target android-8 --pat... Generates

    file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  38. Hello world! $ android create project --target android-8 --pat... Generates

    file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  39. Hello world! $ android create project --target android-8 --pat... Generates

    file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  40. Hello world! $ android create project --target android-8 --pat... Generates

    file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ ruboto gen app --package presentation.hello_world Generates file src/hello_world_activity.rb
  41. Hello world! $ android create project --target android-8 --pat... Generates

    file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ ruboto gen app --package presentation.hello_world Generates file src/hello_world_activity.rb
  42. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } } $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  43. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.app.Activity; import android.widget.TextView; class HelloWorldActivity extends Activity def onCreate( bundle) t = new TextView(this); t.setText(“Hello World!”); setContentView(t); end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  44. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.app.Activity; import android.widget.TextView; class HelloWorldActivity extends Activity def onCreate( bundle) t = TextView.new(this); t.setText(“Hello World!”); setContentView(t); end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  45. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.app.Activity; import android.widget.TextView; class HelloWorldActivity extends Activity def onCreate( bundle) t = TextView.new(self); t.setText(“Hello World!”); setContentView(t); end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  46. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.app.Activity; import android.widget.TextView; class HelloWorldActivity < Activity def onCreate( bundle) t = TextView.new(self); t.setText(“Hello World!”); setContentView(t); end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  47. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.app.Activity import android.widget.TextView class HelloWorldActivity < Activity def onCreate( bundle) t = TextView.new(self) t.setText(“Hello World!”) setContentView(t) end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  48. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.widget.TextView class HelloWorldActivity def onCreate( bundle) t = TextView.new(self) t.setText(“Hello World!”) setContentView(t) end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  49. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.widget.TextView class HelloWorldActivity def onCreate(bundle) t = TextView.new(self) t.setText(“Hello World!”) setContentView(t) end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  50. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb import android.widget.TextView class HelloWorldActivity def on_create(bundle) t = TextView.new(self) t.text = “Hello World!” setContentView(t) end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  51. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb ruboto_import_widget :TextView class HelloWorldActivity def on_create(bundle) t = text_view text: ‘Hello World!' setContentView(t) end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  52. Hello world! $ ruboto gen app --package presentation.hello_world Generates file

    src/hello_world_activity.rb ruboto_import_widget :TextView class HelloWorldActivity def on_create(bundle) setContentView(text_view text: ‘Hello World!') end end $ android create project --target android-8 --pat... Generates file src/presentation/HelloWorldActivity.java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; class HelloWorldActivity extends Activity { public void onCreate(Bundle bundle) { TextView t = new TextView(this); t.setText(“Hello World!”); setContentView(t); } }
  53. Questions?

  54. Examples Make a call Show webpage Spycam

  55. Display a web page import "android.content.Intent" import "android.net.Uri" class RubotoHomePageActivity

    def on_resume intent = Intent.new(Intent::ACTION_VIEW) uri = Uri.parse("http://ruboto.org/") intent.setData(uri) startActivity(intent) end end
  56. Phone home import "android.content.Intent" import "android.net.Uri" class PhoneHomeActivity def on_resume

    intent = Intent.new(Intent::ACTION_CALL) uri = Uri.parse("tel:5551234") intent.setData(uri) startActivity(intent) end end
  57. Spycam Start a WEBrick web server Access the camera

  58. Spycam Start a WEBrick web server Access the camera require

     'monitor' require  'camera_helper' require  'ruboto/util/stack' class  SpycamServer    extend  MonitorMixin    PORT  =  4567    DOC_ROOT  =  "#{$activity.files_dir.absolute_path}/"    @@server  =  nil    def  self.start(activity,  server_status_view)        Thread.with_large_stack(512)  do            synchronize  do                if  @@server.nil?                    activity.run_on_ui_thread  {  server_status_view.text  =   "Loading"  }                    require  'webrick'                    activity.run_on_ui_thread  {  server_status_view.text  =   "Loaded"  }                    @@server  =  WEBrick::HTTPServer.new(:Port  =>   PORT,  :DocumentRoot  =>  DOC_ROOT)                    @@server.mount_proc('/')  do  |req,  resp|                        case  req.path                        when  '/',  'index.html'                            CameraHelper.take_picture(activity)                            resp.content_type  =  "text/html"                            resp.body  =  '<html>                                                            <head>                                                                <title>Spycam</title>                                                            </head>                                                            <body>                                                                <a  href="/"><img  src="latest.jpg"></a>                                                            </body>                                                        </html>'                            raise  WEBrick::HTTPStatus::OK                        when  '/latest.jpg'                            resp.content_type  =  "image/jpg"                            resp.body  =  $camera_data                            $camera_data  =  nil                            raise  WEBrick::HTTPStatus::OK                        else                            resp.body  =  "Unknown  path:  #{req.path.inspect}"                            raise  WEBrick::HTTPStatus::NotFound                        end                    end                    server  =  @@server                    Thread.new{server.start} require  'ruboto/activity' require  'ruboto/widget' require  'spycam_server' import  android.util.Log import  android.view.Surface import  android.view.WindowManager ruboto_import_widgets  :Button,  :LinearLayout,  :ScrollView,  :TextView ruboto_import_widget  :SurfaceView,  "android.view" class  SpycamActivity    def  on_create(bundle)        rotation  =  {                Surface::ROTATION_0  =>  0,Surface::ROTATION_90  =>   90,Surface::ROTATION_180  =>  180,Surface::ROTATION_270  =>  270        }[window_manager.default_display.rotation]        self.title  =  "Spycam  #{rotation}"        #   self.setRequestedOrientation(android.content.pm.ActivityInfo::SCREEN_OR IENTATION_PORTRAIT)        window.add_flags(WindowManager::LayoutParams::FLAG_KEEP_SCREEN_ON)        setContentView(linear_layout(:orientation  =>  :vertical)  do            linear_layout  do                text_view  :text  =>  "Server:  "                @server_status_view  =  text_view            end            linear_layout  do                text_view  :text  =>  "Picture:  "                @camera_status_view  =  text_view            end            sv  =  surface_view            sv.holder.add_callback  RubotoSurfaceHolderCallback.new(rotation)            #  Deprecated,  but  still  required  for  older  API  version            sv.holder.set_type   android.view.SurfaceHolder::SURFACE_TYPE_PUSH_BUFFERS        end)    end        def  set_camera_status(value)        @camera_status_view.text  =  value    end    def  camera_status=(value)        run_on_ui_thread  {  $activity.set_camera_status  value  }    end    def  on_resume   class  CameraHelper    def  self.take_picture(activity)        activity.camera_status  =  "Set  volume..."        am  =   activity.getSystemService(android.content.Context::AUDIO_SERVICE)        old_volume  =   am.get_stream_volume(android.media.AudioManager::STREAM_SYSTEM)        am.set_stream_volume(android.media.AudioManager::STREAM_SYSTEM,  0,   0)        activity.camera_status  =  "Taking  picture..."        picture_taken  =  false        $camera.take_picture(nil,  nil)  do  |data,  camera|            $camera_data  =  String.from_java_bytes(data)            activity.camera_status  =  "Gotcha!"            $camera.start_preview            am.set_stream_volume(android.media.AudioManager::STREAM_SYSTEM,   old_volume,  0)            picture_taken  =  true        end        sleep  0.1  until  picture_taken    end end
  59. Demo: Spycam

  60. Limitations Ruby class cannot directly subclass Java class Tiny stack

    on main thread Startup time Runtime size No AOT/JIT compilation
  61. Status Ruboto is in production! Almost monthly releases. Still improving

    the API Support Android 2.1 - 4.1 5 active developers, more welcome!
  62. Roadmap 1.0.0 release this year? Dalvik backend for the IR

    compiler Direct subclassing of Java classes AOT Compilation / IR Persistence Mirah integration ( http://www.mirah.org ) FFI support Eclipse plugin
  63. Contributors welcome! ruboto.org

  64. Questions?

  65. Thank you!