Friday, January 02, 2009

Solved: Ubuntu 8.04 64 bit, Eclipse 3.4, Subclipse 1.4.7 and Subversion 1.5

A previous post, a possible solution to the problem of installing Subversion support in Eclipse 3.4 on Ubuntu 8.04 64 bit.
Although this worked much better Eclipse is still crashing under some operations. I've detected a problem while developing an android application, checked out from a subversion repository, when R.java is recreated causing Eclipse to crash.

This time, and convinced to find a solution or being forced to use Windows Vista as a development platform, I paid more attention to the crash log.

#
# An unexpected error has been detected by Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007fbacc7e525a, pid=29545, tid=1098688848
#
# Java VM: Java HotSpot(TM) 64-Bit Server VM (10.0-b23 mixed mode linux-amd64)
# Problematic frame:
# V [libjvm.so+0x1f125a]
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

--------------- T H R E A D ---------------

Current thread (0x00000000401a7400): JavaThread "CompilerThread1" daemon [_thread_in_native, id=29552, stack(0x00000000416ca000,0x00000000417cb000)]

siginfo:si_signo=SIGSEGV: si_errno=0, si_code=1 (SEGV_MAPERR), si_addr=0x0000000000000000

Registers:
RAX=0x0000000000000000, RBX=0x00007fba8c561068, RCX=0x00007fba9a4ef5b0, RDX=0x0000000000000050
RSP=0x00000000417c6d70, RBP=0x00000000417c6de0, RSI=0x00007fba9a4ef5b0, RDI=0x00007fba8c561068
R8 =0x00007fba9a4ef608, R9 =0x00007fba9a4ef5b0, R10=0x00007fba9a4ef5b0, R11=0x0000000000000000
R12=0x00007fba8c561030, R13=0x0000000000000000, R14=0x0000000040162f50, R15=0x0000000000000001
RIP=0x00007fbacc7e525a, EFL=0x0000000000010246, CSGSFS=0x0000000000000033, ERR=0x0000000000000004
TRAPNO=0x000000000000000e

Top of Stack: (sp=0x00000000417c6d70)
0x00000000417c6d70: 00007fba9b0d1358 00000001ffffffff
0x00000000417c6d80: 00007fba9a4ef5b0 00000002cc789361
0x00000000417c6d90: 00007fba9b0d1350 00000007417c79a0
0x00000000417c6da0: 00000000417c7a68 01000000000005d2
0x00000000417c6db0: 00000000417c79a0 00007fbacce2e970
0x00000000417c6dc0: 00000000417c79a0 00000000417c6f30
0x00000000417c6dd0: 00000000417c6ef0 00000000417c6ec0
0x00000000417c6de0: 00000000417c7000 00007fbacc7e479c
0x00000000417c6df0: 00000000417c7a68 00000000417c6fb0
0x00000000417c6e00: 00007fba8c3e8010 00007fba8c000020
0x00000000417c6e10: 00000000417c6e80 00007fbacce47d70
0x00000000417c6e20: 00007fba8c104a50 0000000000000174
0x00000000417c6e30: 00000000417c7ac0 00007fbaccfe6c1c
0x00000000417c6e40: 00000000417ca950 00000000417c6e80
0x00000000417c6e50: 00007fbacce4a4e0 00007fba9a80ff90
0x00000000417c6e60: 0000000000000174 00007fbaccc1edf2
0x00000000417c6e70: 0000000040111030 00007fbaccc1eec1
0x00000000417c6e80: 00000000417ca950 00000000417c6ec0
0x00000000417c6e90: 00007fbacce4a4e0 0000000000007fe8
0x00000000417c6ea0: 00007fba8c39f620 00007fbaccc1edf2
0x00000000417c6eb0: 0000000040111030 00007fbaccc1eec1
0x00000000417c6ec0: 00007fbacce2e970 00007fba0000000e
0x00000000417c6ed0: 00000000417c9350 00000000417c79a0
0x00000000417c6ee0: 0000000000000a05 00000000401a79a0
0x00000000417c6ef0: 000000000000000d 00000000417c9350
0x00000000417c6f00: 00007fba8c5bad00 00007fbacc788d00
0x00000000417c6f10: 00007fba8c54f5a0 00000000000005d3
0x00000000417c6f20: 00000000417c6fb0 00007fba8c11dc70
0x00000000417c6f30: 000000000000000c 00000000417c9350
0x00000000417c6f40: 00007fba8c19c360 00007fba8c2d3790
0x00000000417c6f50: 00007fba8c0d9750 00007fba8c0da3b0
0x00000000417c6f60: 00007fba9bd08e60 00000000417c7ac0

Instructions: (pc=0x00007fbacc7e525a)
0x00007fbacc7e524a: 48 89 cf 41 ff 95 80 00 00 00 48 89 df 49 89 c5
0x00007fbacc7e525a: 8b 00 41 21 44 24 38 41 8b 45 04 21 43 04 41 8b

Stack: [0x00000000416ca000,0x00000000417cb000], sp=0x00000000417c6d70, free space=1011k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0x1f125a]
V [libjvm.so+0x1f079c]
V [libjvm.so+0x2445f5]
V [libjvm.so+0x241105]
V [libjvm.so+0x1e05f7]
V [libjvm.so+0x248f98]
V [libjvm.so+0x248936]
V [libjvm.so+0x62a819]
V [libjvm.so+0x624ac1]
V [libjvm.so+0x50630a]


Current CompileTask:
C2:1124 org.eclipse.core.internal.dtree.DataTreeNode.forwardDeltaWith([Lorg/eclipse/core/internal/dtree/AbstractDataTreeNode;[Lorg/eclipse/core/internal/dtree/AbstractDataTreeNode;Lorg/eclipse/core/internal/dtree/IComparator;)[Lorg/eclipse/core/internal/dtree/AbstractDataTreeNode; (469 bytes)


--------------- P R O C E S S ---------------

Java Threads: ( => current thread )
0x00007fbaa47d7800 JavaThread "org.eclipse.jdt.internal.ui.text.JavaReconciler" daemon [_thread_blocked, id=30170, stack(0x0000000041d08000,0x0000000041e09000)]
0x0000000040347000 JavaThread "Worker-11" [_thread_blocked, id=30132, stack(0x0000000040e0c000,0x0000000040f0d000)]
0x00007fba9c43c400 JavaThread "Worker-10" [_thread_blocked, id=30131, stack(0x000000004100e000,0x000000004110f000)]
0x00007fba9bec9800 JavaThread "Worker-9" [_thread_blocked, id=29647, stack(0x0000000041210000,0x0000000041311000)]
0x00007fbaa69c5c00 JavaThread "SVN Kit 1.2 Connector" [_thread_blocked, id=29611, stack(0x000000004245a000,0x000000004255b000)]
0x00007fba9becf800 JavaThread "Thread-14" [_thread_blocked, id=29609, stack(0x0000000042359000,0x000000004245a000)]
0x00007fbaa623a000 JavaThread "Timer-1" [_thread_blocked, id=29607, stack(0x000000004110f000,0x0000000041210000)]
0x00007fbaa43b9000 JavaThread "Worker-8" [_thread_blocked, id=29602, stack(0x0000000042258000,0x0000000042359000)]
0x00007fba9dda5400 JavaThread "Worker-7" [_thread_blocked, id=29601, stack(0x0000000040f0d000,0x000000004100e000)]
0x00007fba9dcd9400 JavaThread "Worker-6" [_thread_in_vm, id=29600, stack(0x0000000041bcf000,0x0000000041cd0000)]
0x00007fba9beec800 JavaThread "Worker-4" [_thread_blocked, id=29598, stack(0x0000000042056000,0x0000000042157000)]
0x00007fbaa498d800 JavaThread "Timer-0" [_thread_blocked, id=29592, stack(0x000000004074d000,0x000000004084e000)]
0x00007fba9af2a800 JavaThread "Device List Monitor" daemon [_thread_in_native, id=29591, stack(0x0000000042157000,0x0000000042258000)]
0x00007fba9da2b800 JavaThread "Monitor" daemon [_thread_in_native, id=29574, stack(0x0000000041f55000,0x0000000042056000)]
0x00007fba9c3e5800 JavaThread "org.eclipse.jdt.internal.ui.text.JavaReconciler" daemon [_thread_blocked, id=29571, stack(0x000000004064c000,0x000000004074d000)]
0x00007fbaa5500800 JavaThread "Java indexing" daemon [_thread_blocked, id=29569, stack(0x0000000041e54000,0x0000000041f55000)]
0x0000000040378c00 JavaThread "Start Level Event Dispatcher" daemon [_thread_blocked, id=29561, stack(0x000000004054b000,0x000000004064c000)]
0x000000004031d800 JavaThread "Framework Event Dispatcher" daemon [_thread_blocked, id=29560, stack(0x0000000041ace000,0x0000000041bcf000)]
0x0000000040437400 JavaThread "State Data Manager" daemon [_thread_blocked, id=29559, stack(0x00000000419cd000,0x0000000041ace000)]
0x00000000401a9000 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=29553, stack(0x00000000417cb000,0x00000000418cc000)]
=>0x00000000401a7400 JavaThread "CompilerThread1" daemon [_thread_in_native, id=29552, stack(0x00000000416ca000,0x00000000417cb000)]
0x000000004019bc00 JavaThread "CompilerThread0" daemon [_thread_blocked, id=29551, stack(0x00000000415c9000,0x00000000416ca000)]
0x000000004019a400 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=29550, stack(0x00000000414c8000,0x00000000415c9000)]
0x0000000040176400 JavaThread "Finalizer" daemon [_thread_blocked, id=29549, stack(0x000000004097a000,0x0000000040a7b000)]
0x0000000040175000 JavaThread "Reference Handler" daemon [_thread_blocked, id=29548, stack(0x0000000040879000,0x000000004097a000)]
0x0000000040113000 JavaThread "main" [_thread_in_vm, id=29546, stack(0x00000000413c7000,0x00000000414c8000)]

Other Threads:
0x000000004016fc00 VMThread [stack: 0x0000000040b09000,0x0000000040c0a000] [id=29547]
0x00000000401ab000 WatcherThread [stack: 0x00000000418cc000,0x00000000419cd000] [id=29554]

VM state:not at safepoint (normal execution)

VM Mutex/Monitor currently owned by a thread: None

Heap
def new generation total 42496K, used 9220K [0x00007fbaa84d0000, 0x00007fbaab2e0000, 0x00007fbaada20000)
eden space 37824K, 14% used [0x00007fbaa84d0000, 0x00007fbaa8a53ac0, 0x00007fbaaa9c0000)
from space 4672K, 76% used [0x00007fbaaa9c0000, 0x00007fbaaad3d7b0, 0x00007fbaaae50000)
to space 4672K, 0% used [0x00007fbaaae50000, 0x00007fbaaae50000, 0x00007fbaab2e0000)
tenured generation total 94144K, used 48464K [0x00007fbaada20000, 0x00007fbab3610000, 0x00007fbab84d0000)
the space 94144K, 51% used [0x00007fbaada20000, 0x00007fbab0974090, 0x00007fbab0974200, 0x00007fbab3610000)
compacting perm gen total 86016K, used 85928K [0x00007fbab84d0000, 0x00007fbabd8d0000, 0x00007fbac84d0000)
the space 86016K, 99% used [0x00007fbab84d0000, 0x00007fbabd8ba3b8, 0x00007fbabd8ba400, 0x00007fbabd8d0000)
No shared spaces configured.

Dynamic libraries:
40000000-40009000 r-xp 00000000 08:05 424775 /usr/lib/jvm/java-6-sun-1.6.0.07/jre/bin/java
40108000-4010a000 rwxp 00008000 08:05 424775 /usr/lib/jvm/java-6-sun-1.6.0.07/jre/bin/java
4010a000-4054b000 rwxp 4010a000 00:00 0 [heap]
4054b000-4054e000 ---p 4054b000 00:00 0
4054e000-4064c000 rwxp 4054e000 00:00 0
4064c000-4064f000 ---p 4064c000 00:00 0

...

VM Arguments:
jvm_args: -Djava.library.path=/usr/share/java/ -Djava.library.path=/usr/lib/jni/ -Dosgi.requiredJavaVersion=1.5 -Xms40m -Xmx256m -XX:MaxPermSize=256m
java_command: /opt/java/eclipse-3.4/plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar -os linux -ws gtk -arch x86_64 -showsplash -launcher /opt/java/eclipse-3.4/eclipse -name Eclipse --launcher.library /opt/java/eclipse-3.4/plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.0.101.R34x_v20080731/eclipse_1115.so -startup /opt/java/eclipse-3.4/plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar -exitdata 1190018 -vm /usr/bin/java -vmargs -Djava.library.path=/usr/share/java/ -Djava.library.path=/usr/lib/jni/ -Dosgi.requiredJavaVersion=1.5 -Xms40m -Xmx256m -XX:MaxPermSize=256m -jar /opt/java/eclipse-3.4/plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar
Launcher Type: SUN_STANDARD

Environment Variables:
PATH=/home/diego/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
USERNAME=diego
LD_LIBRARY_PATH=/usr/lib/jvm/java-6-sun-1.6.0.07/jre/lib/amd64/server:/usr/lib/jvm/java-6-sun-1.6.0.07/jre/lib/amd64:/usr/lib/jvm/java-6-sun-1.6.0.07/jre/../lib/amd64:/usr/lib64/xulrunner-addons
SHELL=/bin/bash
DISPLAY=:0.0

Signal Handlers:
SIGSEGV: [libjvm.so+0x661750], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGBUS: [libjvm.so+0x661750], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGFPE: [libjvm.so+0x504550], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGPIPE: SIG_IGN, sa_mask[0]=0x00000000, sa_flags=0x00000000
SIGXFSZ: [libjvm.so+0x504550], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGILL: [libjvm.so+0x504550], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGUSR1: SIG_DFL, sa_mask[0]=0x00000000, sa_flags=0x00000000
SIGUSR2: [libjvm.so+0x5067c0], sa_mask[0]=0x00000000, sa_flags=0x10000004
SIGHUP: [libjvm.so+0x506520], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGINT: [libjvm.so+0x506520], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGTERM: [libjvm.so+0x506520], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
SIGQUIT: [libjvm.so+0x506520], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004


--------------- S Y S T E M ---------------

OS:lenny/sid

uname:Linux 2.6.24-22-generic #1 SMP Mon Nov 24 19:35:06 UTC 2008 x86_64
libc:glibc 2.7 NPTL 2.7
rlimit: STACK 8192k, CORE 0k, NPROC 12221, NOFILE 1024, AS infinity
load average:0.49 0.31 0.27

CPU:total 2 (2 cores per cpu, 1 threads per core) family 6 model 15 stepping 6, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3

Memory: 4k page, physical 1537752k(21980k free), swap 3148700k(3103580k free)

vm_info: Java HotSpot(TM) 64-Bit Server VM (10.0-b23) for linux-amd64 JRE (1.6.0_07-b06), built on Jun 10 2008 01:53:27 by "java_re" with gcc 3.2.2 (SuSE Linux)

time: Mon Dec 29 22:56:29 2008
elapsed time: 490 seconds



As we can see, the problem is not in subclipse or subversive but in the java virtual machine. It's true, that the problem only showed up when we use subversion, but this is another story.
So, to obtain the solution, download jdk-6u11-linux-x64.bin from Sun and install it.
Next step is to tell Eclipse to use this newly installed java.
Edit eclipe.ini and add these lines

-showsplash
org.eclipse.platform
-vm
/opt/java/jdk1.6/bin/java
-vmargs
-Djava.library.path=/usr/share/java/
-Djava.library.path=/usr/lib/jni/
-Dosgi.requiredJavaVersion=1.5
-Xms40m
-Xmx256m
-XX:MaxPermSize=256m



Problem solved !
No crashes till now...

Android Intent Playground 2.0 (Installation)

These are the simplest steps to install Android Intent Playground using the emulator.


Download site
Go to http://codtech.com/downloads/android and download AndroidIntentPlayground.apk.
To be able to download it you need to attach an sdcard image to the emulator using -sdcard sdcard.img.

Install blocked
Click on the recently downloaded application to install it.
If you receive an Install blocked message you have to enable installation of applications form unknown sources, not only from Android Market.



Enable installation from unknown sources
Go to Settings and enable Unknown sources.

Install application
Once the settings are correct the application can be installed.



Launch the application
After being successfully installed launch the application and you will be presented with Android Intent Playground main screen.



Play with intents
Fell free to play with intents. Using Menu -> Random is a good way to get started.

Sunday, December 28, 2008

Ubuntu 8.04 64 bit, Eclipse 3.4, Subclipse 1.4.7 and Subversion 1.5

How to get these working together ?
Firstly, it's incredible that such a simple thing requires such a big amount of research, trial and error and frustration when should work out-of-the-box.
I'm writing this post hoping to save somebody else precious development time.

Introduction
Subclipse 1.4.7 requires Subversion 1.5 which is not available in normal Ubuntu repositories.
Eclipse just crashes using other combinations, in this environment.

Subversion 1.5
Install subversion 1.5 from Ubuntu backports. Just download the required packages and install them, there's no need to enable backports repository just for this.
Download the following packages:
  • subversion (> 1.5)
  • libsvn1 (>1.5)
  • libsvn-java (>1.5)
and install them using dpkg, for example in 64 bit

$ sudo dpkg --install libsvn-java_1.5.1dfsg1-1ubuntu2_amd64.deb \
libsvn1_1.5.1dfsg1-1ubuntu2_amd64.deb \
subversion_1.5.1dfsg1-1ubuntu2_amd64.deb

Subclipse 1.4.7
Add http://subclipse.tigris.org/update_1.4.x site to Eclipse and install Subclipse 1.4.7, Subversion Client Adapter 1.5.2 and Subversion Native Client Library Adapter (JavaHL) 1.5.5

Configuring Eclipse 3.4
If you try to use Subversion in Eclipse you will receive and error, because the Subversion JNI libraries are not detected.
To achieve thisd you have to edit eclipse.ini (the path depends on where you've decided to install it, as it's not installed from deb packages)
Add these two lines (this is the little magic)

-showsplash
org.eclipse.platform
-vmargs
-Djava.library.path=/usr/share/java/
-Djava.library.path=/usr/lib/jni/
-Dosgi.requiredJavaVersion=1.5
-Xms40m
-Xmx256m
-XX:MaxPermSize=256m

and, after restarting Eclipse, you will be able to use Subversion.
Verify that under SVN Interface the correct JavaHL version is detected in Window -> Preferences -> Team -> SVN.

Android Intent Playground 2.0

Android Intent Playground 2.0 was released.


Check the previous post too: Diego Torres Milano's blog: Android: Playing with Intents which refers to a previous version.



This new version includes some extra features to help you understand and test Android intents.

Installation
Use the method described in Diego Torres Milano's blog: Android Intent Playground 2.0 installation or download AndroidIntentPlayground.apk and install it on the emulator using

adb install AndroidIntentPlayground.apk


Usage
After successful installation the launcher icon appear on the main screen


Launch Intent Playground and the main screen appears

we can tailor an Intent, filling some of its attributes, and then do something with it for example starting the corresponding application.
Among these Intent attributes we can set






















actionthe general action of the Intent, such as ACTION_VIEW, ACTION_EDIT, ACTION_MAIN, etc.
attributethe data to operate on, specified as an (attribute, value) pair.
Can be a

  • data uri
  • category
  • mime type

valuethe actual value to complete the (attribute, value) pair as specified in attribute
intentspecifies what to do with the intent

  • start an activity
  • broadcast the intent
  • start a service
  • resolve the activity

activitythe resolved activity


Random intents
There's a menu option to fill in random values, from a pre built list, of intent attributes

Wednesday, December 24, 2008

ge2adt new release

In this previous post, we reviewed Google Earth to Android ADT  (ge2adt) a simple application to convert Google Earth's KML routes to a format suitable to be loaded into Android ADT Emulator Control.
ge2adt has been updated to allow the conversion directly from Google Earth's KMZ routes, avoiding the unzipping step.

Friday, December 19, 2008

Android, Google Earth and KML routes

Whilst testing location based applications, the need to simulate routes is likely to appear.
This article shows you how to obtain KML routes using Google Earth, convert it to a suitable format to be loaded into Eclipse ADT plugin Emulator Control and be able to test location based applications.

Create the route
Using Google Earth, create the route using Directions.

Then right click on Route, at the end of the list of directions, and save it. Let's say, we save it as myroute.kmz.

Convert the route
To be used with the current version of Android ADT plugin (0.8.0) a slightly different format is needed as is not supported.
We have to convert the route to use multiple s.

The change is really simple and we could do it manually, but fortunately there's an application to automate this task.
ge2adt is hosted on Google Appengine and can be reached at http://ge2adt.appspot.com/.
Use your Google identifier to access it (i.e.: you gmail account).

Unzip kmz, extract doc.kml, rename it, upload myroute.kml, convert it, and save the result as myroute-adt.kml.

Test my location
Using Eclipse Android DDMS perspective, under Emulator Control, load the converted KML file myroute-adt.kml.


Once the route is loaded, use you location based application or launch Maps, select My Location on the menu, press the play button on Emulator Control and you will be able to appreciate the map moving along the route.



Wednesday, December 03, 2008

Android Development Workshop slides

I was a great opportunity to present this at Mobile Dev Camp, if you couldn't attend, 
presentation slides are available at http://www.slideshare.net/pr1001/android-development-workshop-presentation

Thursday, November 20, 2008

Android workshop at Mobile Dev Camp

I was kindly invited by Bubble Foundry's Peter Robinett to give a workshop on Android at Mobile Dev Camp this 29th November 2008 in Amsterdam.
We will be introducing the Android platform and how to start developing applications keeping an eye on Test Driven Development. 
More information and registration can be found at http://www.mobiledevcamp.nl/?p=41

Looking forward to seeing you.

Sunday, November 09, 2008

Android: Testing on the Android platform - ApiDemos tests











This document can be read in Google Docs (http://docs.google.com/Doc?id=ddwc44gs_49stmqs7hb), cut and paste link.





A previous post,Android: Testing on the Android platform - Unit tests, showed how to add your tests and run them from inside Eclipse. Although these are very useful tests in our quest to Test Driven Development, they cover only a small part of our needs.

Android 1.0 introduced a whole new world of tests cases like ActivityUnitTestCase to run isolated unit tests, ServiceTestCase to tests services and even functional test of activities like ActivityInstrumentatonTestCase.



ApiDemos provides a set of tests but you will not be able to easily run them unless in a non convoluted way as the way they are structured it's not supported by current Android Development Tools (ADT) Eclipse plugin and you would need other tools, but the solution is so simple that I wonder why they are not originally provided in the way we will be changing them.

Google documentation is not helping either.



ApiDemos tests


Tests are located in the tests/src folder and they have their corresponding AndroidManifest.xml.

Inside this folder, tests like this one are found










/*

 * Copyright (C) 2008 Google Inc.

 */



package com.example.android.apis;



import android.test.ActivityInstrumentationTestCase;



/**

 * Make sure that the main launcher activity opens up properly, which will be

 * verified by {@link ActivityInstrumentationTestCase#testActivityTestCaseSetUpProperly}.

 */

public class ApiDemosTest extends ActivityInstrumentationTestCase<ApiDemos> {



    public ApiDemosTest() {

        super("com.example.android.apis", ApiDemos.class);

    }



}







but we will not be able to run them not resorting to ant or maven, unless we make the following set of changes.

ApiDemosTest Android project




Create new project


Let's create a new Android project from within Eclipse, as usual New -> Project -> Android -> Android Project






Activity and Application name are set to Dummy because they are not used as we are seeing shortly.



Copy ApiDemos tests




Copy the tests/src folder from te original ApiDemos project and turn it into a source folder.

Fix the project setup to use original ApiDemos project to resolve references.






Copy AndroidManifest.xml


Again, from the original ApiDemos project copy AndroidManifest.xml overwriting the existing one






Build and run



If necessary, remove ApiDemos.apk if it has been already installed in the emulator.

Build ApiDemos and ApiDemosTests projects and install them.

Now, if you execute Dev Tools in the emulator and go to Instrumentation, you'll find Test for Api Demos. in the list.








Select it and you will obtain the tests results. Unfortunatelly by now, the reslts will be only visible in the logcat window









11-09 22:56:35.132: INFO/instrumentation(153): Test results for InstrumentationTestRunner=......................

11-09 22:56:35.132: INFO/instrumentation(153): Time: 6.739

11-09 22:56:35.132: INFO/instrumentation(153): OK (22 tests)






or alternativelly, from the command line

$ adb shell am instrument -w com.example.android.apis.tests/android.test.InstrumentationTestRunner

com.example.android.apis.ApiDemosApplicationTests:....

com.example.android.apis.ApiDemosTest:.

com.example.android.apis.app.ForwardingTest:...

com.example.android.apis.app.LocalServiceTest:.....

com.example.android.apis.os.MorseCodeConverterTest:.

com.example.android.apis.view.Focus2ActivityTest:....

com.example.android.apis.view.Focus2AndroidTest:....

Test results for InstrumentationTestRunner=......................

Time: 7.493



OK (22 tests)


Conclusion


So simple that I can't understand why they are not provided in this way by the original Android ApiDemos project.

Next time we will try to present test results in a more concise way inside the emulator as Electro did (video1, video2, video3).









Thursday, November 06, 2008

Android: Testing on the Android platform - Unit tests

This is the first installment of a series of articles about testing on the Android platform. Things have changed with the release of the version 1.0 of the SDK and will change in the future for sure, as there are still some lose ends.
Electron and Positron frameworks are not valid anymore in this new SDK, so let's back to base and start analyzing the possibilities featured in the Android platform as it is.


As with previous version of articles covering testing for different platforms we will be using our simple Temperature Converter (also analyzed in Test Driven Development and GUI Testing) example.

For a Test Driven Development approach you should
  1. create your Android project
  2. add the tests source folder (New -> Source Folder -> Folder name: tests/src)
  3. in the newly created folder add a Java Package. Its name should be the same as the project package with .tests appended
  4. in the 'tests' package create a new JUnit Test Case using JUnit 3 (New -> JUnit Test Case). Name it TemperatureConverterTest, leave class under test blank
  5. Copy this code into TemperatureConverterTest.java 
package com.codtech.android.temperatureconverter.tests;

      import junit.framework.TestCase;

          import java.util.HashMap;
            import java.util.Map;

                import com.codtech.android.temperatureconverter.TemperatureConverter;

                    /**
                       * @author diego
                         *
                           */
                            public class TemperatureConverterTest extends TestCase {

                                private static final Map conversionTable = new HashMap();

                                    static {
                                      // initialize (c, f) pairs
                                        conversionTable.put(0, 32);
                                          conversionTable.put(100, 212);
                                            conversionTable.put(-1, 30);
                                              conversionTable.put(-100, -148); conversionTable.put(32, 90);
                                                conversionTable.put(-40, -40);
                                                  conversionTable.put(-273, -459);
                                                    }

                                                        /**
                                                          * @param name
                                                            */
                                                              public TemperatureConverterTest(String name) { super(name);
                                                                }


                                                                      /**
                                                                        * Test method for {@link com.codtech.android.temperatureconverter.TemperatureConverter#celsiusToFahrenheit(int)}.
                                                                          */
                                                                            public void testCelsiusToFahrenheit() {
                                                                              for (int c: conversionTable.keySet()) {
                                                                                int f = conversionTable.get(c);
                                                                                  String msg = "" + c + "C -> " + f + "F"; int r = TemperatureConverter.celsiusToFahrenheit(c);
                                                                                    assertEquals(msg, f, r);
                                                                                      }
                                                                                        }
                                                                                          }

                                                                                          1. Accept Eclipse hints to create TemperatureConverter class and celsiusToFahrenheit method
                                                                                          2. Run -> Run As -> Run configurations and create a new JUnit configuration and select the previously created Test class
                                                                                          3. Run the tests and instead of the expected test results you'll get
                                                                                            # An unexpected error has been detected by Java Runtime Environment:
                                                                                              #
                                                                                                #  Internal Error (classFileParser.cpp:2924), pid=5364, tid=6644
                                                                                                  #  Error: ShouldNotReachHere
                                                                                                  1. That's because we are using Android's JUnit stub implementation. Go to Run -> Run As -> Run configurations again and in the recently created JUnit configuration Classpath's Bootstrap Entries remove Android Library
                                                                                                  2. Then Add Library, using Advanced... button, and add JRE System Library and JUnit 3
                                                                                                  3. Apply and Run
                                                                                                  4. And now our tests run, failing as expected. We haven't created the conversion method anyway





                                                                                                  So far so good, our tests are running. But as you may have discovered already, mainly when we changed the libraries, those tests are not Android platform tests so they are only useful as part of our Test Driven Development strategy and we must have always in mind that real Android implementation of some functionality may vary.

                                                                                                  1. Let's finish our TemperatureConverter class
                                                                                                  2. package com.codtech.android.temperatureconverter;

                                                                                                    /**
                                                                                                       * @author diego
                                                                                                         *
                                                                                                           */
                                                                                                            package com.codtech.android.temperatureconverter;
                                                                                                              public class TemperatureConverter {
                                                                                                                public static final int ABSOLUTE_ZERO_C = -273;

                                                                                                                    public static int celsiusToFahrenheit(int c) {
                                                                                                                      if (c < ABSOLUTE_ZERO_C ) {
                                                                                                                      throw new RuntimeException("Invalid temperature: " + c + " below absolute zero");
                                                                                                                      }
                                                                                                                      return (int)Math.round(c * 1.8 + 32);
                                                                                                                      }
                                                                                                                      }

                                                                                                                      Run the test again and it will success. A Test Suite can allso be added, however in this case as we have only one test it's not necessary.

                                                                                                                      Stay tuned. Next article will explore Android Instrumentation to run tests on the real platform.


                                                                                                                      Tuesday, September 16, 2008

                                                                                                                      Android thin client

                                                                                                                      Is Google Android suitable as a thin client operating system ?
                                                                                                                      I've been designing and developing thin client OSs during the last 7 years, and I was wondering if we can base a thin client OS on Android.
                                                                                                                      Let's find out.

                                                                                                                      Well, we need to change some source code to enable network booting so we have to wait, but watching this crude preview (from an 800x600 screen) perhaps begins our brainstorm...



                                                                                                                      Comments and suggestions are gladly welcome.

                                                                                                                      Thursday, September 04, 2008

                                                                                                                      from Z to A

                                                                                                                      Or from Zenity to Autoglade.
                                                                                                                      Gnome bug #412493 has been there for more than a year, it refers to the ability of handling forms with zenity. There are some proposals, but far too way too complex.
                                                                                                                      And sometimes, simple problems deserves simple solutions...

                                                                                                                      As usual, create your form in Glade, we will use the same example described in the bug report, a simple login window for a downloader pretending being connected to ftp.bli.org.
                                                                                                                      This is the running application.
                                                                                                                      The entry fields are annotated with autoglade as:
                                                                                                                      • username:auto:init:env
                                                                                                                      • password:auto:init:env
                                                                                                                      to initialize the values from the corresponding environment variables.

                                                                                                                      We use this simple script (login.sh) to call autoglade using login.glade

                                                                                                                      #! /bin/sh
                                                                                                                      export username=$LOGNAME
                                                                                                                      ${AUTOGLADE:-autoglade} ${0%.sh}.glade

                                                                                                                      That simple.

                                                                                                                      Tuesday, September 02, 2008

                                                                                                                      Lists meet autoglade

                                                                                                                      The latest autoglade (available from svn repository) now supports lists as a special case of a GtkTreeView widget usng a ListStore model with a single column. Remember, as always, it's a zero programming solution.

                                                                                                                      As other widgets, lists can be initialized from the environment using autoglade annotation to its name, for example:

                                                                                                                      treeview1:auto:init:env

                                                                                                                      will use the environment variable treeview1 to obtain list header and items

                                                                                                                      export treeview1='("Fruits" "Apples" "Bananas" "Hedge aple" "Kiwifruits" "Melons" "Oranges" "Pineapples" "Strawberries" )'

                                                                                                                      Using one of the tests also present in the svn repository

                                                                                                                      $ ./list.sh


                                                                                                                      and, after selecting one item and pressing OK

                                                                                                                      treeview1='("Kiwifruits")'
                                                                                                                      autoargs='$treeview1'

                                                                                                                      appears in application's stdout.

                                                                                                                      More information about autoglade can be obtained from http://autoglade.sf.net.

                                                                                                                      Google Chrome


                                                                                                                      This is taken from Google Chrome browser presentation.
                                                                                                                      There was ?

                                                                                                                      Fell free to interpret.

                                                                                                                      Monday, August 04, 2008

                                                                                                                      autoglade

                                                                                                                      This document can be read in Google Docs (http://docs.google.com/Edit?tab=view&docid=ddwc44gs_458qnjwvgr)


                                                                                                                      Introduction

                                                                                                                      This article will guide you through the steps needed to provide a graphical user interface (GUI) to some commands requiring almost no programming using autoglade.

                                                                                                                      As a real life example we will be using some commands to control cpu frequency scaling in Asus EeePC.
                                                                                                                      EeePC features a Celeron-M (4G) with On Demand Frequency Modulation (ODFM) originally set to performance, which actually disables ODFM and fixes CPU speed to 900 MHz (or 630 MHz, as it's underclocked in BIOS prior to 8804).

                                                                                                                      From some post in eeeuser forum:
                                                                                                                      "The cpu in the EEE consumes the same wattage running idle at 900mhz(630 real) as it does running idle at the 'scaled' frequency of 112.5mhz, because the actual frequency *does not change* it's just the forced execution of halt instructions. Halt instructions do save power; when a halt instruction is executed the cpu gets a bit of 'rest' where it consumes significantly less power than if it was executing a complex SSE2 instruction."

                                                                                                                      ODFM additionally provides ondemand mode. Available governors can be obtained using this command
                                                                                                                      $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
                                                                                                                      ondemand performance
                                                                                                                      current scaling governor can be obtained with
                                                                                                                      $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
                                                                                                                      performance
                                                                                                                      as well as maximum allowed frequency
                                                                                                                      $ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
                                                                                                                      900000
                                                                                                                      While it's not completely clear if you can save some power and extend battery life using ondemand scaling or limiting the maximum frequency, we will be using this example to create a GUI around these commands and you can test for yourself. Anyway, our final objective is the creation of the GUI and analyzing the patterns used in order to be able to reproduce this with other commands lacking a GUI.

                                                                                                                      autoglade

                                                                                                                      autoglade is a tool that will take our GUI design and will automate most common usage patterns to be able to give the GUI functionality with no programming.

                                                                                                                      Design the GUI

                                                                                                                      We will be using another computer to design the GUI where glade user interface builder version 3 is installed. There's nothing wrong installing glade-3 on the EeePC, but the screen would be too small to confortably design the interface and you may need an external monitor.
                                                                                                                      glade-3 it's available for Linux and Windows, and because the GUI is described as an XML file it's platform independent.

                                                                                                                      This is an overview of the GUI, in this particular case using glade-3 on Windows Vista
                                                                                                                      our expanded widget tree should be something like this.

                                                                                                                      We can see some widget that have been highlighted. These widgets have received special names.

                                                                                                                      This is one of the way that autoglade uses to receive some messages from our design. Let's review them.
                                                                                                                      We have an horizontal scale widget whose name is freq:auto:init:env, that is our widget name is freq, because we are going to change the cpu frequency using it and we ask autoglade (auto) to initialize it (init) using the process environment (env) and by default autoglade will look for a variable named after the widget name (freq). Its value will be taken form the environment upon startup and the horizontal scale will be initialized having this value.

                                                                                                                      Next, we have two radio buttons to set the scaling governor to performance or ondemand.
                                                                                                                      Radio buttons are named as an incremental sequence, for example name1, name2, name3, ..., namen. In this particular case the name is governor.
                                                                                                                      In all but the first one we have to set the group property to be able to operate them as a group, that is only one can be active at a time.
                                                                                                                      As explained before the names are governor1:auto:init:env and governor2:auto:init:env, because they are the first (1) and second (2) radio buttons of the group, and we ask autoglade (auto) to initinalize (init) them using the process environment (env). In this case the variable will be governor and depending on its value (performance or ondemand) the corresponding radio will be activated on startup.

                                                                                                                      We need to send a message to autoglade to tell it how do we want to exit the event loop and thus closing the dialog and passing a value to its parent process. We do this by setting the response ID on OK and Cancel buttons to RESPONSE_OK (-5) and RESPONSE_CANCEL (-6).

                                                                                                                      Running with autoglade

                                                                                                                      Let's save it as cpufreq.glade and we are ready to test it.
                                                                                                                      $ autoglade cpufreq.glade
                                                                                                                      and most of the required behavior of our GUI is already there.

                                                                                                                      Specifying initial values

                                                                                                                      You can specify the initial value for frequency
                                                                                                                      $ freq=500 autoglade cpufreq.glade
                                                                                                                      or for both frequency and governor
                                                                                                                      $ freq=130 governor=ondemand autoglade cpufreq.glade

                                                                                                                      Obtaining return values

                                                                                                                      Running autoglade in one of the previously mentioned froms will give us these results
                                                                                                                      freq='225'
                                                                                                                      governor='ondemand'
                                                                                                                      autoargs='$freq $governor'
                                                                                                                      to standard output with the values we have selected in the GUI.

                                                                                                                      Shell wrapper

                                                                                                                      We are now in condition of putting everything togheter with a shell wrapper script.
                                                                                                                      Let's start with a simple one and then we can add more sophisticated features.
                                                                                                                      #! /bin/bash

                                                                                                                      AUTOGLADE=autoglade # set absolute path if autoglade is not installed

                                                                                                                      CPUFREQDIR=/sys/devices/system/cpu/cpu0/cpufreq

                                                                                                                      freq()
                                                                                                                      {
                                                                                                                      # get or set freqency
                                                                                                                      local F=$CPUFREQDIR/scaling_max_freq
                                                                                                                      local S=1000

                                                                                                                      [ -n "$1" ] && echo $(( $1 * $S )) > $F || export freq=$(( $(< $F) / $S ))
                                                                                                                      }

                                                                                                                      governor()
                                                                                                                      {
                                                                                                                      # get or set governor
                                                                                                                      local F=$CPUFREQDIR/scaling_governor

                                                                                                                      [ -n "$1" ] && echo "$1" > $F || export governor=$(< $F)
                                                                                                                      }

                                                                                                                      freq
                                                                                                                      governor

                                                                                                                      DUMP=$( $AUTOGLADE cpufreq.glade )
                                                                                                                      if [ $? -eq 0 ]
                                                                                                                      then
                                                                                                                      eval "$DUMP"
                                                                                                                      freq $freq
                                                                                                                      governor $governor
                                                                                                                      fi


                                                                                                                      Previous wrapper illustrates various common patterns.
                                                                                                                      Next time, we will be using more advanced features to finish our cpufreq application.

                                                                                                                      Monday, July 14, 2008

                                                                                                                      Vista on Asus EeePC


                                                                                                                      You can find tons of post about installing Vista on Asus EeePC, and some videos too. So, perhaps it works.
                                                                                                                      But, wait a minute !
                                                                                                                      What's the reason to install Vista ?
                                                                                                                      Because this Xandros sucks, because you can't configure it to your liking...
                                                                                                                      It's no news that AsusLauncher is very bad designed and, for example, instead of highlighting icons when the mouse is over it's using completely different images. So for every icon, you need a copy of it, highlighted multiplied by the number of themes. A total waste of disk space in such a limited environment.
                                                                                                                      Living with that limitations, and tweaking the glorious IceWM and some images and AsusLauncher XML comfiguration, you can obtain veeesta (a Vista looking EeePC running Xandros Linux).
                                                                                                                      I would have installed Ubuntu, but once that I have a Linux notebook where all of its hardware is working out-of-the-box, as if it was a Windows one, I don't want to start hunting for tweaks on how to make the wireless network work, how to make it sleep, or whatever.

                                                                                                                      If you want some instructions on how to do it, just drop me a message.
                                                                                                                      I think that this wallpapers and images cannot be redistributed due to Microsoft copyrights.

                                                                                                                      Enjoy veeesta !

                                                                                                                      Ohh, I almost forgot to show you the themed firefox and taskbar...

                                                                                                                      Monday, April 14, 2008

                                                                                                                      Android Developer Challenger: Electron yet another demo

                                                                                                                      As promised in Android Developer Challenger: Electron and a slightly more interesting demo here you are !
                                                                                                                      Another Electron demo, this time we have an extremely simple Web Activity application driven from the Electron test web service.



                                                                                                                      We can see in this test how we start the activity, wait for its progress until loaded completely, scroll down, follow a link and finishing.

                                                                                                                      What kind of application being tested would you like to see ?

                                                                                                                      Android Developer Challenger: Electron and a slightly more interesting demo

                                                                                                                      In my previous post about Android Developer Challenger: Electron Acceptance and Unit Testing Framework we could watch some demos about two simple cases.
                                                                                                                      Here I'm presenting a slightly more interesting one: driving the Touch Paint application through the test web service.
                                                                                                                      I hope you enjoy it.



                                                                                                                      We can see how the activity is started, non-fade is selected from the menu, pointer commands are sent and translated to events by Electron and finally fade is enabled, wait some time and the application is finished.

                                                                                                                      Still, more to come.

                                                                                                                      Saturday, April 12, 2008

                                                                                                                      Android Developer Challenger: Electron Acceptance and Unit Testing Framework

                                                                                                                      My first intention was to submit a different application, but in the process of developing this application and trying to apply Test Driven Development and Design techniques, I found that although Google is providing JUnit in Android, it was not fully supported, fully documented, fully whatever.

                                                                                                                      Some Unit Tests can be run in Eclipse, but you were not be testing on the real target. So be careful on that.

                                                                                                                      Google also provides application instrumentation code through Instrumentation class. When running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml's .

                                                                                                                      In the process of writing my own library and tools, I discovered Phil Smith's positron an Open Source library, so I decided to extend his excellent work and bring some new and missing pieces to the table.

                                                                                                                      And although positron is the anti-particle of the electron, and they annihilate if collide, take for granted that it's not the idea here, but more the conservation of the energy and the generation of some "visible light and waves".

                                                                                                                      Featured components

                                                                                                                      Android Electron Acceptance And Unit Tests
                                                                                                                      Android Electron Acceptance and Unit Test contains some sample applications and their tests:
                                                                                                                      • Temperature Converter
                                                                                                                      • Touch Paint
                                                                                                                      • Web Activity
                                                                                                                      Android Electron Test Results
                                                                                                                      Android Electron Test Results is the application used to display test results.
                                                                                                                      In this video demonstration, Temperature Converter application is tested and some tests failures are showed, because the temperature conversion function is not yet implemented and returns always zero, as an step in the Test Driven Development process.



                                                                                                                      There's also a web service like interface to drive the tests, as showed in this video.




                                                                                                                      Electron-JavaSE
                                                                                                                      Electron Java SE version to drive the tests from the development environment. The ZIP contains the needed components to run Electron, Javadocs and some sample test scripts.

                                                                                                                      Tests can be scripted, and for example, the test we saw in the video demonstration before can be written as

                                                                                                                      #! /usr/bin/env electron
                                                                                                                      start?package=com.codtech.android&\
                                                                                                                      class=com.codtech.android.adc.tdd.TemperatureConverterActivity

                                                                                                                      press 123
                                                                                                                      DOWN
                                                                                                                      DOWN
                                                                                                                      CLICK
                                                                                                                      @celsius.text
                                                                                                                      assert 123
                                                                                                                      @fahrenheit.text
                                                                                                                      assert 253 123C_=>_253F
                                                                                                                      finish
                                                                                                                      Stay tuned. More on Electron later.

                                                                                                                      Saturday, March 22, 2008

                                                                                                                      Automating port redirection in Android

                                                                                                                      If you are developing an application that uses port redirection you should open the emulator's console and issue the redir commands every time you restart the emulator. This is documented by Google in android emulator page.
                                                                                                                      To redirect port you need to
                                                                                                                      telnet localhost 5554

                                                                                                                      to open the emulator's console and then add the desired redirection commands, like
                                                                                                                      redir add tcp:5000:5000

                                                                                                                      But, is there another way than typing the commands every time ?
                                                                                                                      It's much likely that you make a mistake and wonder why your application stopped working until you realize your typing mistake.
                                                                                                                      I couldn't find any other documented way of automating port redirection, so I decided to go my way.

                                                                                                                      Python to the rescue
                                                                                                                      This is clearly a task for expect, but instead of trying to remember how to program TCL I decided to go with the python alternative: pexpect.

                                                                                                                      The script is named, pretty obviously, android-redir.py:

                                                                                                                      Download the script from here.

                                                                                                                      #!/usr/bin/env python
                                                                                                                      """
                                                                                                                      $Id$
                                                                                                                      """

                                                                                                                      __license__ = """

                                                                                                                      Copyright (C) 2008 Diego Torres Milano

                                                                                                                      This program is free software; you can redistribute it and/or modify
                                                                                                                      it under the terms of the GNU General Public License as published by
                                                                                                                      the Free Software Foundation; either version 2 of the License, or
                                                                                                                      (at your option) any later version.

                                                                                                                      This program is distributed in the hope that it will be useful,
                                                                                                                      but WITHOUT ANY WARRANTY; without even the implied warranty of
                                                                                                                      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
                                                                                                                      GNU General Public License for more details.

                                                                                                                      You should have received a copy of the GNU General Public License
                                                                                                                      along with this program; if not, write to the Free Software
                                                                                                                      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
                                                                                                                      USA
                                                                                                                      """

                                                                                                                      __name__ = 'android port redirection'
                                                                                                                      __version__ = '0.3'
                                                                                                                      __rev__ = '$Revision$'

                                                                                                                      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                                                      # redirections can be added to ~/android/redir.conf, one per line,
                                                                                                                      # as an example, 'tcp:5000:6000' will route any packet sent to the host's
                                                                                                                      # TCP port 5000 to TCP port 6000 of the emulated device
                                                                                                                      #
                                                                                                                      # default emulated device:
                                                                                                                      host = 'localhost'
                                                                                                                      port = 5554
                                                                                                                      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                                                                                                                      import sys
                                                                                                                      import os
                                                                                                                      from optparse import OptionParser
                                                                                                                      import pexpect

                                                                                                                      usage = "usage: %prog [options] [{tcp|udp}:hostport:emuport] ..."

                                                                                                                      parser = OptionParser(usage=usage, version="%prog " + __version__)
                                                                                                                      parser.add_option("-v", "--verbose", dest="verbose", default=False,
                                                                                                                      action="store_true",
                                                                                                                      help="verbose output [default: %default]")
                                                                                                                      parser.add_option("", "--host", dest="host", default=host,
                                                                                                                      help="HOST where emulator is running [default: %default]")
                                                                                                                      parser.add_option("-p", "--port", dest="port", default=port,
                                                                                                                      help="emulator console PORT [default: %default]")
                                                                                                                      parser.add_option("-n", "--dry-run", dest="dry_run", default=False,
                                                                                                                      action="store_true",
                                                                                                                      help="Don't execute the commands")
                                                                                                                      (options, args) = parser.parse_args()

                                                                                                                      redirs = []
                                                                                                                      cmd = 'telnet %s %d' % (options.host, options.port)

                                                                                                                      try:
                                                                                                                      for redir in open(os.path.expanduser("~") + "/.android/redir.conf"):
                                                                                                                      redirs.append(redir[:-1])
                                                                                                                      except:
                                                                                                                      pass

                                                                                                                      for redir in args:
                                                                                                                      redirs.append(redir)

                                                                                                                      if options.verbose:
                                                                                                                      print cmd
                                                                                                                      if len(redirs) > 0:
                                                                                                                      print "adding redirections:"
                                                                                                                      for redir in redirs:
                                                                                                                      print "\t" + redir

                                                                                                                      if options.dry_run:
                                                                                                                      sys.exit(0)

                                                                                                                      if len(redirs) == 0:
                                                                                                                      print >>sys.stderr, "ERROR: redirection list is empty."
                                                                                                                      sys.exit(1)

                                                                                                                      child = pexpect.spawn(cmd)
                                                                                                                      child.expect("OK")

                                                                                                                      for redir in redirs:
                                                                                                                      child.sendline("redir add " + redir)
                                                                                                                      r = child.expect(["OK", "KO: host port already active", "KO:.*"])
                                                                                                                      if r == 2:
                                                                                                                      raise Exception(child.after)

                                                                                                                      if options.verbose:
                                                                                                                      child.sendline("redir list")
                                                                                                                      child.expect("OK")
                                                                                                                      print child.before

                                                                                                                      child.sendline("quit")


                                                                                                                      Usage
                                                                                                                      This is the script help showing its usage, accessible by
                                                                                                                      $ android-redir.py --help
                                                                                                                      Usage: android-redir.py [options] [{tcp|udp}:hostport:emuport] ...

                                                                                                                      Options:
                                                                                                                      --version show program's version number and exit
                                                                                                                      -h, --help show this help message and exit
                                                                                                                      -v, --verbose verbose output [default: False]
                                                                                                                      --host=HOST HOST where emulator is running [default: localhost]
                                                                                                                      -p PORT, --port=PORT emulator console PORT [default: 5554]
                                                                                                                      -n, --dry-run Don't execute the command


                                                                                                                      You can also create ~/.android/redir.conf file and add the redirections you want, one per line
                                                                                                                      tcp:5000:5000
                                                                                                                      udp:50001:50001


                                                                                                                      and they will be read every time the script is run.


                                                                                                                      Next time we will be looking at how to integrate this with the emulator to run both commands at the same time.