Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruboto - JRuby on Android at JRubyConf.eu 2012

Ruboto - JRuby on Android at JRubyConf.eu 2012

Uwe Kubosch

August 17, 2012
Tweet

More Decks by Uwe Kubosch

Other Decks in Programming

Transcript

  1. Ruboto? Builds on JRuby and Android Application and component generators

    Compact GUI definition Rake based development Test framework
  2. Activity: A screen View: A screen component Service: Background process

    Intent: Definition of action BroadcastReceiver: Listener for Intents Android basics/terms
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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.
  11. 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.
  12. Tooling - Install and run APK rake install rake start

    rake install start rake update_scripts:restart
  13. Hello world! $ android create project --target android-8 --path hello_world

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

    --package presentation.hello_world --activity HelloWorldActiv Generates file src/presentation/HelloWorldActivity.java
  15. 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); } }
  16. 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>
  17. 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); } }
  18. 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); } }
  19. 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); } }
  20. 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
  21. 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
  22. 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); } }
  23. 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); } }
  24. 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); } }
  25. 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); } }
  26. 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); } }
  27. 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); } }
  28. 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); } }
  29. 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); } }
  30. 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); } }
  31. 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); } }
  32. 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); } }
  33. 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
  34. 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
  35. 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
  36. Limitations Ruby class cannot directly subclass Java class Tiny stack

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

    the API Support Android 2.1 - 4.1 5 active developers, more welcome!
  38. 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