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
    JRuby on Android

    View full-size slide

  2. Uwe Kubosch
    Work at Datek Wireless in
    Norway
    Ruboto core developer
    JRuby rookie committer

    View full-size slide

  3. Ruboto?
    Builds on JRuby and
    Android
    Application and
    component generators
    Compact GUI definition
    Rake based development
    Test framework

    View full-size slide

  4. Topics covered
    History
    Ruboto IRB
    Installation & development
    tools
    Hello world!
    SpyCam
    Limitations
    Roadmap

    View full-size slide

  5. Activity: A screen
    View: A screen component
    Service: Background process
    Intent: Definition of action
    BroadcastReceiver: Listener for Intents
    Android basics/terms

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  11. Demo: OpenGL

    View full-size slide

  12. History 2010
    ruboto-core : GSoC 2010 by Daniel Jackoway
    Version 0.0.3 released december 19, 2010

    View full-size slide

  13. 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

    View full-size slide

  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

    View full-size slide

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

    View full-size slide

  16. 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

    View full-size slide

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

    View full-size slide

  18. 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

    View full-size slide

  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
    $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

    View full-size slide

  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
    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

    View full-size slide

  21. 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

    View full-size slide

  22. Tooling
    The “ruboto” command
    Rake

    View full-size slide

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

    View full-size slide

  24. 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.

    View full-size slide

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

    View full-size slide

  26. 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.

    View full-size slide

  27. Tooling - build APK
    rake debug
    rake release

    View full-size slide

  28. Tooling - Install and run APK
    rake install
    rake start
    rake install start
    rake update_scripts:restart

    View full-size slide

  29. Hello World!

    View full-size slide

  30. Hello world!

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  33. 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);
    }
    }

    View full-size slide

  34. 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);
    }
    }

    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"
    >
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!" />

    View full-size slide

  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);
    }
    }

    View full-size slide

  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);
    }
    }

    View full-size slide

  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);
    }
    }

    View full-size slide

  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);
    }
    }
    $ ruboto gen app --package presentation.hello_world
    Generates file src/hello_world_activity.rb

    View full-size slide

  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);
    }
    }
    $ ruboto gen app --package presentation.hello_world
    Generates file src/hello_world_activity.rb

    View full-size slide

  40. 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);
    }
    }

    View full-size slide

  41. 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);
    }
    }

    View full-size slide

  42. 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);
    }
    }

    View full-size slide

  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 = 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);
    }
    }

    View full-size slide

  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 < 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);
    }
    }

    View full-size slide

  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 < 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);
    }
    }

    View full-size slide

  46. 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);
    }
    }

    View full-size slide

  47. 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);
    }
    }

    View full-size slide

  48. 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);
    }
    }

    View full-size slide

  49. 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);
    }
    }

    View full-size slide

  50. 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);
    }
    }

    View full-size slide

  51. Examples
    Make a call
    Show webpage
    Spycam

    View full-size slide

  52. 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

    View full-size slide

  53. 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

    View full-size slide

  54. Spycam
    Start a WEBrick web server
    Access the camera

    View full-size slide

  55. 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  =  '
                                                               
                                                                   Spycam
                                                               
                                                               
                                                                   
                                                               
                                                           '
                               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

    View full-size slide

  56. Demo: Spycam

    View full-size slide

  57. Limitations
    Ruby class cannot directly
    subclass Java class
    Tiny stack on main thread
    Startup time
    Runtime size
    No AOT/JIT compilation

    View full-size slide

  58. Status
    Ruboto is in production!
    Almost monthly releases.
    Still improving the API
    Support Android 2.1 - 4.1
    5 active developers, more welcome!

    View full-size slide

  59. 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

    View full-size slide

  60. Contributors welcome!
    ruboto.org

    View full-size slide