Tuesday, December 20, 2011

Just posted a plugin to use JRuby from SBT.  Pretty limited right now, but potentially useful.  Available on github as sbt-jruby.

Wednesday, October 26, 2011

Brief review of gadgets from Google IO 2011, five months later

At Google IO 2011, swag was received.  Two things really stand out:

Samsung Galaxy Tab 10.1 This rocks.  I use it constantly.  It’s a great dev device, too, since it’s really fast.  (That does require also using dev code on an el cheapo phone too – my choice for that are a couple Samsung Europas I bought in Ireland for E50.)  The only “problem” is that I have to compete with my wife for the device.  We’ve got a Fire on order that should solve that problem.  (I’d buy another Galaxy, but as a developer I feel like I need lots of new devices.  My wife laughs when she hears that.)

Chromebook.  I can’t even be bothered to find a link to these things.  I tried to use it, but it’s slow and has a nasty screen.  Feels like an obsolete laptop I discarded a couple years ago.  I don’t even know where it is, and I realized I can’t even tell you how long it’s been missing.

Sunday, September 25, 2011

Using the jruby eclipse plugin to generate an interface implemention

I started using asm to put together some ruby code generation scripts for the Eclipse plugin.  This one prints out a list of method definitions and their java signatures when you select an interface in the package explorer. If you select this interface
package com.restphone.jrubyeclipse;

import org.eclipse.jface.viewers.ISelection;

public interface IJrubyFilter {
  String do_filter(ISelection s);

  Integer someOtherMethod();
}
You'll get this output:
java_signature "java.lang.String do_filter (org.eclipse.jface.viewers.ISelection a)"
def do_filter *args
end

java_signature "java.lang.Integer someOtherMethod ()"
def someOtherMethod *args
end
Checked in to github as ruby_filter_interface.rb.

Friday, September 23, 2011

More JRuby + asm

Turns out you can get this jruby from yesterday's post even more concise:
require 'java'
require 'asm-3.3.1'
require 'pp'

# This lets me type org.objectweb.asm::... instead of Java::OrgObjectwebAsm::...
def org
  Java::Org
end

class SampleVisitor
  include org.objectweb.asm::MethodVisitor
  include org.objectweb.asm::ClassVisitor
  include org.objectweb.asm::FieldVisitor
  include org.objectweb.asm::AnnotationVisitor
  include org.objectweb.asm.signature::SignatureVisitor

  def method_missing name, *args
    name_string = name.to_s
    if name_string =~ /visit.*/
      puts "#{name}\t#{args}"
      self
    else
      super
    end
  end
end

# Loop through each .class file given on the command line
ARGV.each do |classfile|
  puts " ---------------- Reading file #{classfile}"
  f = java.io.File.new classfile
  fis = java.io.FileInputStream.new f
  
  class_reader = org.objectweb.asm::ClassReader.new fis
  
  v = SampleVisitor.new
  
  class_reader.accept v, 0
  
  puts
end
And the output is:
---------------- Reading file /Users/james/experimements/AsmSample/bin/com/restphone/classSignature/SampleOne.class
visit   [50, 33, "com/restphone/classSignature/SampleOne", nil, "java/lang/Object", #<#<Class:0x1144f3ba2>:0x2f6a23cf>]
visitSource     ["SampleOne.java", nil]
visitField      [9, "x", "Ljava/lang/Integer;", nil, nil]
visitEnd        []
visitMethod     [8, "<clinit>", "()V", nil, nil]
visitCode       []
visitLabel      [#<Java::OrgObjectwebAsm::Label:0x2b071e12>]
visitLineNumber [4, #<Java::OrgObjectwebAsm::Label:0x2b071e12>]
visitFieldInsn  [178, "com/restphone/classSignature/SampleTwo", "y", "Ljava/lang/Integer;"]
visitFieldInsn  [179, "com/restphone/classSignature/SampleOne", "x", "Ljava/lang/Integer;"]
visitLabel      [#<Java::OrgObjectwebAsm::Label:0x575c13ef>]
visitLineNumber [3, #<Java::OrgObjectwebAsm::Label:0x575c13ef>]
visitInsn       [177]
visitMaxs       [1, 0]
visitEnd        []
visitMethod     [1, "<init>", "()V", nil, nil]
visitCode       []
visitLabel      [#<Java::OrgObjectwebAsm::Label:0xc303a60>]
visitLineNumber [3, #<Java::OrgObjectwebAsm::Label:0xc303a60>]
visitVarInsn    [25, 0]
visitMethodInsn [183, "java/lang/Object", "<init>", "()V"]
visitInsn       [177]
visitLabel      [#<Java::OrgObjectwebAsm::Label:0x66869470>]
visitLocalVariable      ["this", "Lcom/restphone/classSignature/SampleOne;", nil, #<Java::OrgObjectwebAsm::Label:0xc303a60>, #<Java::OrgObjectwebAsm::Label:0x66869470>, 0]
visitMaxs       [1, 1]
visitEnd        []
visitMethod     [1, "doubleTheValue", "(Ljava/lang/Integer;)Ljava/lang/Integer;", nil, nil]
visitCode       []
visitLabel      [#<Java::OrgObjectwebAsm::Label:0x10fa706d>]
visitLineNumber [7, #<Java::OrgObjectwebAsm::Label:0x10fa706d>]
visitVarInsn    [25, 1]
visitMethodInsn [182, "java/lang/Integer", "intValue", "()I"]
visitInsn       [5]
visitInsn       [104]
visitMethodInsn [184, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"]
visitInsn       [176]
visitLabel      [#<Java::OrgObjectwebAsm::Label:0x629a99eb>]
visitLocalVariable      ["this", "Lcom/restphone/classSignature/SampleOne;", nil, #<Java::OrgObjectwebAsm::Label:0x10fa706d>, #<Java::OrgObjectwebAsm::Label:0x629a99eb>, 0]
visitLocalVariable      ["x", "Ljava/lang/Integer;", nil, #<Java::OrgObjectwebAsm::Label:0x10fa706d>, #<Java::OrgObjectwebAsm::Label:0x629a99eb>, 1]
visitMaxs       [2, 2]
visitEnd        []
visitEnd        []
I'm including the jars on the command line:
jruby -I /Users/james/experimements/AsmSample/libs --1.9 asm_support.rb /Users/james/experimements/AsmSample/bin/com/restphone/classSignature/SampleOne.class  | less

Thursday, September 22, 2011

JRuby + Asm: easy processing of .class files

I started working with Asm this week.  After playing with it for a bit, it seemed obvious that JRuby would be a sweet spot for Asm code; very often, you need to implement only a small fraction of the interfaces that Asm uses.

Here’s my first JRuby effort with Asm.  It’s straightforward and doesn’t do much yet – just outputs the contents of the .class files given on the command line.  Here’s the JRuby:

require 'java'
require 'asm-3.3.1'
require 'pp'

# This lets me type org.objectweb.asm::... instead of Java::OrgObjectwebAsm::...
def org
  Java::Org
end

# This lets me use ClassReader without typing out org.objectweb.asm::ClassReader
java_import org.objectweb.asm::ClassReader

# Ruby supports mixins.  Both visitor classes (class and method) use this method_missing
# call.
#
# The generic visitor just prints information for any call to a visitor* method.
module GenericVisitor
  def method_missing *args
    if args.first.to_s =~ /visit.*/
      puts "In type: #{self.class} call to " + args.to_s
    else
      super
    end
  end
end

class SampleMethodVisitor
  include org.objectweb.asm::MethodVisitor
  include GenericVisitor
end

class SampleClassVisitor
  include org.objectweb.asm::ClassVisitor
  include GenericVisitor
  
  # we need to keep a copy of our method visitor
  def initialize args
    @method_visitor = args[:method_visitor]
  end
  
  def visit_method *args
    # The output has methods seperated with an easy-to-see string
    puts "visit method " + args.to_s + "================================"
      
    # Asm wants ClassVisitor#visitMethod to return a method visitor 
    @method_visitor
  end
end

# Loop through each .class file given on the command line
ARGV.each do |classfile|
  puts " ---------------- Reading file #{classfile}"
  f = java.io.File.new classfile
  fis = java.io.FileInputStream.new f
  
  class_reader = ClassReader.new fis
  
  v = SampleClassVisitor.new method_visitor: SampleMethodVisitor.new
  
  class_reader.accept v, 0
  
  puts
end

And here’s the output:

---------------- Reading file /Users/james/experimements/AsmSample/bin/com/restphone/classSignature/SampleOne.class
In type: SampleClassVisitor call to [:visit, 50, 33, "com/restphone/classSignature/SampleOne", nil, "java/lang/Object", #<#<Class:0x12690ed81>:0x28b53b32>]
In type: SampleClassVisitor call to [:visitSource, "SampleOne.java", nil]
In type: SampleClassVisitor call to [:visitField, 9, "x", "Ljava/lang/Integer;", nil, nil]
visit method [8, "<clinit>", "()V", nil, nil]================================
In type: SampleMethodVisitor call to [:visitCode]
In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x236954e1>]
In type: SampleMethodVisitor call to [:visitLineNumber, 4, #<Java::OrgObjectwebAsm::Label:0x236954e1>]
In type: SampleMethodVisitor call to [:visitFieldInsn, 178, "com/restphone/classSignature/SampleTwo", "y", "Ljava/lang/Integer;"]
In type: SampleMethodVisitor call to [:visitFieldInsn, 179, "com/restphone/classSignature/SampleOne", "x", "Ljava/lang/Integer;"]
In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x643f58bb>]
In type: SampleMethodVisitor call to [:visitLineNumber, 3, #<Java::OrgObjectwebAsm::Label:0x643f58bb>]
In type: SampleMethodVisitor call to [:visitInsn, 177]
In type: SampleMethodVisitor call to [:visitMaxs, 1, 0]
In type: SampleMethodVisitor call to [:visitEnd]
visit method [1, "<init>", "()V", nil, nil]================================
In type: SampleMethodVisitor call to [:visitCode]
In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x1d7aaa0e>]
In type: SampleMethodVisitor call to [:visitLineNumber, 3, #<Java::OrgObjectwebAsm::Label:0x1d7aaa0e>]
In type: SampleMethodVisitor call to [:visitVarInsn, 25, 0]
In type: SampleMethodVisitor call to [:visitMethodInsn, 183, "java/lang/Object", "<init>", "()V"]
In type: SampleMethodVisitor call to [:visitInsn, 177]
In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x13ad9b0f>]
In type: SampleMethodVisitor call to [:visitLocalVariable, "this", "Lcom/restphone/classSignature/SampleOne;", nil, #<Java::OrgObjectwebAsm::Label:0x1d7aaa0e>, #<Java::OrgObjectwebAsm::Label:0x13ad9b0f>, 0]
In type: SampleMethodVisitor call to [:visitMaxs, 1, 1]
In type: SampleMethodVisitor call to [:visitEnd]
visit method [1, "doubleTheValue", "(Ljava/lang/Integer;)Ljava/lang/Integer;", nil, nil]================================
In type: SampleMethodVisitor call to [:visitCode]
In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x9eae15f>]
In type: SampleMethodVisitor call to [:visitLineNumber, 7, #<Java::OrgObjectwebAsm::Label:0x9eae15f>]
In type: SampleMethodVisitor call to [:visitVarInsn, 25, 1]
In type: SampleMethodVisitor call to [:visitMethodInsn, 182, "java/lang/Integer", "intValue", "()I"]
In type: SampleMethodVisitor call to [:visitInsn, 5]
In type: SampleMethodVisitor call to [:visitInsn, 104]
In type: SampleMethodVisitor call to [:visitMethodInsn, 184, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"]
In type: SampleMethodVisitor call to [:visitInsn, 176]
In type: SampleMethodVisitor call to [:visitLabel, #<Java::OrgObjectwebAsm::Label:0x2569a1c5>]
In type: SampleMethodVisitor call to [:visitLocalVariable, "this", "Lcom/restphone/classSignature/SampleOne;", nil, #<Java::OrgObjectwebAsm::Label:0x9eae15f>, #<Java::OrgObjectwebAsm::Label:0x2569a1c5>, 0]
In type: SampleMethodVisitor call to [:visitLocalVariable, "x", "Ljava/lang/Integer;", nil, #<Java::OrgObjectwebAsm::Label:0x9eae15f>, #<Java::OrgObjectwebAsm::Label:0x2569a1c5>, 1]
In type: SampleMethodVisitor call to [:visitMaxs, 2, 2]
In type: SampleMethodVisitor call to [:visitEnd]
In type: SampleClassVisitor call to [:visitEnd]

Incidentally, I used my new Eclipse plugin to send the current selection through a filter to html-escape the text.  Check it out on github.

Tuesday, August 23, 2011

Mobile market in Ireland - Android and iPhone

I'm on vacation in Ireland right now, and the mobile market here is interesting and different.

First, unlike Seattle where every other storefront sells coffee, in Ireland every other shop is a mobile phone operator.  They're everywhere. 

And the really big difference is prepaid.  I picked up a Samsung Europa for €49, no contract.  "Locked" to 3, but only if you're not capable of searching "unlock" on google.  (Yes, the number 3 is an Irish telecom company.)  For €20, the "topup" includes unlimited data for a month, unlimited 3-3 calling/texting,  and 29c/minute out of network, free on weekends.  Every tiny little shop in the country sells minutes, too, so it's trivial to buy more.

If I lived here and had even a tiny bit of patience, that same Europa goes for €39 delivered.  (And they sell for more than that on ebay.  My wife said we're on vacation, and I'm not supposed to pack 200 of them in my suitcase to resell at a profit.  Shame.  I did point this out to the young guy in the 3 shop though, and he looked thoughtful.)

It's an Android 2.2 device.  It's not great (no multitouch, small screen, slow compared to my wife's Nexus One), but it's OK.

The iPhone is a nice chunk of hardware, but it's €569 - TEN TIMES the price of an Android phone.  Yes, you can get it for free on a contract, but it's a middle-class extravagance.  If you think you might be worried about cash next month, I don't see how you buy one.

I had no idea how much cheaper Android phones were over here.  I'm not seeing a whole lot of iPhones; it's not like home.


Oh, and if you do bring an unlocked Android GSM phone with you, they'll tell you the unlimited data for €20 plan doesn't work for tethering.  Works great, though. 

Monday, May 16, 2011

Notes on Android Market for Developers session at Google I/O 2011


Notes on Android Market for Developers session at Google I/O 2011

(For Google I/O Show and Tell http://www.meetup.com/seattle-gtug/events/16361982/)

- James Moore, james@restphone.com

Session video is up at http://www.google.com/events/io/2011/sessions/android-market-for-developers.html
  • Growth
    • 400k activations/day for Android devices worldwide
    • 60% of activiations are outside USA
    • He emphasized Korea and Japan
    • Up from 100k/day YOY
    • App installs
      • 8x from 2009 -> 2010
      • 2011 as of today is slightly more than all of 2010
    • Charts around 3:08 in video
  • Apps are used by Gingerbread and Honeycomb
    • New device users == heavy consumers of applications
    • graph at 6:30
  • Recent installs of apps (trending categories)
    • Games
    • Entertainment
    • Tools
    • Media
    • Travel and local
    • Transportation
  • Trending Paid apps categories (8:46)
    • Games
    • Tools
    • Personalization
    • Productivity
    • Entertainment
    • Medical
    • Comics
    • Shopping
  • New OS versions are most of the app downloads 10:32
    • They see two versions of Android dominant over time (the two change as new releases come out)
    • Today
      • 25% 2.1
      • 75% 2.2
    • developer.android.com has lots of numbers for things like versions, screensizes
    • Major vendors committed to 18 month upgrade guarantees, announced at IO2011
  • Quick demos of (14:49)
    • Pulse News
    • Angry Birds
    • Gun Brothers
    • Talked about approaches to OS version dependencies
  • 90% of Android devices hitting the market have OpenGS 2.0
  • New market tools offer better targeting
    • Devices, geography, screensize, etc
  • Coming soon
    • Multiple apks (23:01) in June
      • One app listing
      • Different screen sizes, etc
      • Multiple apks
      • Aggregates billing, rating, comments
    • Large apks 24:23
      • 4GB total
      • 50 meg apk plus 2 x 2GB bundles downloaded separtelly
  • One-click integration with AdMob, already launched
  • Lots of new lists on Marketplace
    • Trending
    • Lists by market
    • Better ways to show all apps from a developer
  • Direct carrier billing is 50% of app sales at one (unnamed) US carrier
  • In-app upgrades are working really well


These notes are up at https://docs.google.com/document/pub?id=1mWJAHkFcP_C91opc9bOKowHye3BgMwk2G-92Mia-MUA

Tuesday, May 3, 2011

Android error: java.lang.Error: packaging failure: closure resource not found

If you're seeing errors like this when you start your Android application: You've compiled with CodePro coverage enabled. Turn it off.

Thursday, April 21, 2011

App Engine debug project gets java.lang.NoSuchMethodError: org.mortbay.thread.Timeout

I see this error sometimes when I'm starting my Google App Engine / GWT project:

Exception in thread "main" java.lang.NoSuchMethodError: org.mortbay.thread.Timeout.(Ljava/lang/Object;)V
 at org.mortbay.io.nio.SelectorManager$SelectSet.(SelectorManager.java:306)
 at org.mortbay.io.nio.SelectorManager.doStart(SelectorManager.java:223)
 at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
 at org.mortbay.jetty.nio.SelectChannelConnector.doStart(SelectChannelConnector.java:303)
 at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
 at org.mortbay.jetty.Server.doStart(Server.java:233)
 at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
 at com.google.gwt.dev.shell.jetty.JettyLauncher.start(JettyLauncher.java:565)
 at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:494)
 at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1058)
 at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:800)
 at com.google.gwt.dev.DevMode.main(DevMode.java:304)

The simple fix is to reset the SDK for App Engine, under Properties > Google > App Engine.  Change it to something other than your current SDK, then change it back.  This doesn't happen often enough for me to figure out what the real fix might be.

Monday, March 28, 2011

Thursday, March 24, 2011

Bookstands for holding dev devices

I’ve just had my dev devices lying on the desk, but I decided I wanted something to hold them up.  Ordered a couple from Amazon.

I ordered the Insight and the Fellows.  I’m using the Insight regularly.  For iPhones, it’s got a nice slot in the back to slip the cable through.  I’m using a Droid as my regular Android dev device, and it’s connector is on the side, so no issues there.  Haven’t tried the Evo yet. 

For the iPhone, it’s not quite stable with the cable plugged in, so I just wrapped a rubber band around it.  Not exactly high design, but works fine.

Both of these are cheap; < $10.

I also ordered a Gorillapod, but it’s not stable enough when you’re punching stuff on the screen.  I liked it enough to keep it, though, just for its intended use (camera tripod).

Insight:

P1010709

P1010708

Fellows

P1010707