Android Developers: adb command completion in bash HOWTO

Roman Nurik, of the Google Android team, has put out a nifty shell extension to make development using adb easier.  If you’re like me, you’re familiar with the basics, like adb install and adb logcat, but adb has lots of sub-commands and it’s nice not to have to look them up at Android’s developer site. This post is a short tutorial for setting up and using the shell extension.

Here’s the home page:
http://code.google.com/p/romannurik-code/source/browse/misc/bash_completion/adb

To use it:

1) Download the raw script from the following URL:
http://romannurik-code.googlecode.com/git/misc/bash_completion/adb

Place it in a folder somewhere (like ~/bin/adb.bash for this example).

2) In your .bashrc or .profile (whichever you use), include the script.  Example:

#
# Enable adb command completion
#
. ~/bin/adb.bash

3) Restart Terminal (Mac), or your shell app (Linux).

4) Now, you can get completion for adb commands.  In the examples below, [TAB key] means I hit the TAB key on the keyboard:

Michaels-MacBook-Air:android mportuesi$ adb [TAB key]
bugreport          install            pull               reboot-bootloader  shell
devices            kill-server        push               remount            start-server
forward            logcat             reboot             root               uninstall
Michaels-MacBook-Air:android mportuesi$ adb l[TAB key]
Michaels-MacBook-Air:android mportuesi$ adb logcat

Update: Android developer Marc Reichelt has put out a similar command completion script for fastboot as well. You can install it the same way.

Posted in Android | Comments closed

ZipDownloader for Android: Download and unpack .zip files

Recently, I implemented some code to download some audio assets that are packaged in a .zip file. When first run, the app downloads these assets from a server (S3 in our case), unpacks them, and stashes them away on the SD card.

This is a typical use case for apps such as games, which have a lot of image and audio assets that must be downloaded separately from the application APK file. This is usually because Google enforces a 50-megabyte limit for Android APK downloads. But also it can be a way to put some of your application on the SD card if you cannot support SD card installation for some reason or another.

Being a lazy developer who works under tight deadlines, I went out searching for some code to unpack .zip files. I found one example that was a good starting point, but it ran very slowly and it didn’t clean up after itself well when it was done.

I have built on that example, and produced a working example app for Android that shows how to implement a background task that will download a .zip file from an internet URL, then unzip the contents to a cache folder on external storage (a.k.a the SD card).

The sample app:

  • Traps errors and cleans up after itself in the event of error
  • Performs all I/O operations (network and filesystem) in the background, for StrictMode compliance
  • Keeps the screen alive while the download is in process
  • Locates the files on external storage in a place which will be automatically deleted by Android on uninstall
  • Uses buffered I/O for efficiency
  • Manages internal data in a way as to (mostly) be friendly to the Dalvik garbage collector.
  • Is compatible with all versions of Android 2.1 through 4.0.  It probably will run on earlier versions of Android, but I haven’t tested.

In short, it is production-ready code.

The sample code is published under the MIT open-source license, and is available on my github repository.

Have fun!

Posted in Android | Comments closed

How to disable Screen Auto-Rotation on Android

By default, most Android apps re-orient themselves when the user rotates the screen on their device.

Many app developers don’t need to think about this at all for their apps, but for the ones who do, you need to understand what Android is doing behind the scenes. Not only is it important for implementing screen rotation yourself, but also for avoiding mysterious bugs and crashes relating to screen rotation.

What Android Normally Does

Android attempts to provide a base means of implementing auto-rotation, so that every app does not have to implement it.

Normally, when the user rotates the device, Android “transparently” handles this situation by destroying the current Activity, and instantiating a new instance of the same activity. For most apps, this works just fine, but there can be some side effects.

By default, the new activity won’t have the runtime state of the old. Your activity must override onSaveInstanceState() to save runtime state from the old instance into a Bundle object. Android passes this bundle into the onCreate() method of the new activity instance, where you can use it to re-populate your member variables and onscreen controls.

Handling Orientation Changes Yourself

If you don’t like Android’s default method for handling screen rotation, you can take matters into your own hands. Set the android:ConfigChanges attribute for your activity in the AndroidManifest.xml file:

<activity android:name="com.myapp.MyActivity"
          android:label="@string/app_name"
          android:configChanges="orientation"
          >
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Here, the orientation flag in android:configChanges tells the system that the Activity wishes to handle rotation on its own. Android will invoke the onConfigurationChanged() method of your Activity instead, which allow you to handle the screen rotation yourself. It will no longer kill and restart your Activity.

Here’s an example onConfigurationChanged() which replaces the main content view for the currently running Activity:

@Override
public void onConfigurationChanged(Configuration newConfig) {
	super.onConfigurationChanged(newConfig);

	// Set a new layout - framework will automatically choose portrait or landscape as needed
	setContentView( R.layout.my_activity_layout );

	// Reconnect all listeners for controls in the layout
	a.findViewById( R.id.exit_button ).setOnClickListener( mListener );
}

Odds are, your onConfigurationChanged() method will need to do almost exactly the same kind of work as your Activity’s onCreate() method, so it’s probably a good idea to DRY out your code by factoring out your layout setup into a separate helper method that you invoke from both onCreate() and onConfigurationChanged().

Forcing Orientation at Build Time

If you wish to force an Activity to always be a particular orientation, you can simply specify its orientation in its entry in AndroidManifest.xml:

<activity android:name="com.myapp.MyActivity"
          android:label="@string/app_name"
          android:screenOrientation="landscape"
          android:configChanges="orientation"
          >
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

The android:screenOrientation attribute forces this activity to be in landscape mode always.

If you use android:screenOrientation to hammer the orientation to portrait or landscape, I highly recommend you combine it with the android:configChanges="orientation" flag to ensure that Android will not kill/restart your Activity on rotation. I have seen some obscure bugs in my app caused by an activity being restarted on rotation, even though android:screenOrientation was set.

When you combine the two flags, you can likely leave your implementation of onConfigurationChanged() blank, as your Activity has nothing to do on screen rotations. (It’s worth noting that onConfigurationChanged() is a more general mechanism that notifies the activity of several other device configuration changes, such as opening/closing a sliding keyboard, and Android will still invoke this callback for the other changes. So obviously your code may vary).

Finally, the android:screenOrientation attribute has some other nifty flags that do nifty things. For instance, you can have the orientation match the orientation of the previous Activity on the activity stack. This is useful if you want to force a particular orientation, but want to do so in the context of other Activities in your app flow.

Forcing Orientation at Run Time

You might have a need to dynamically lock the orientation – that is, choose between landscape or portrait at runtime, rather than build time. You can use the method Activity#setRequestedOrientation() for this purpose.

Here’s a code example for a method on an Activity subclass, that hammers the activity orientation to portrait at runtime:

protected void setOrientation() {
	int current = getRequestedOrientation();
	// only switch the orientation if not in portrait
	if ( current != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ) {
		setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_PORTRAIT );
	}
}

If you invoke setRequestedOrientation(), Android assumes you have opted out of screen orientation updates altogether for this activity, and it will no longer invoke onConfigurationChanged() to notify your Activity of screen rotation changes.

Posted in Android | Comments closed

More about keeping Android’s screen awake

In my previous post, I discussed the pros and cons of the various means of keeping the screen alive in Android, focusing mainly on the need for sandbox permissions in your application’s AndroidManifest.xml file.

In this post, I’d like to further elaborate on the “shortcut” techniques to allow you to keep the screen alive, without explicitly managing a Wake Lock in your application.

FLAG_KEEP_SCREEN_ON

I’ve already covered the technique of setting a flag on your Activity’s main window to keep the screen active:

getWindow().addFlags( WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON );

There are two things to keep in mind with this approach:

  1. FLAG_KEEP_SCREEN_ON only works when the app window is onscreen.  If the user switches apps, Android automatically releases the wake lock.  That might be fine for your use case, but if you have a long-running background task that really needs to keep the device running until finished, this isn’t an airtight approach.
  2. FLAG_KEEP_SCREEN_ON does just that; it keeps the screen active along with the rest of the device.  If you directly create and manage a raw wake lock in your own code, you have more granularity, for example allowing the screen to go dim or go off completely whilst still allowing the CPU to do its thing.

I won’t discuss how to create and manage a Wake Lock directly; instead, I’ll refer you to the SDK docs and to a short code example (I happen to like the anddev.org site for its nice, short and useful code snippets).

android:keepScreenOn

Although I haven’t tried this in my own dev work, you can also enforce “screen always on” behavior on a per-view basis.

Every view has an android:keepScreenOn attribute that you can use to keep the screen active whenever the view is visible.  This should be as easy as simply setting the attribute in the XML layout you use to define your views, plus it needs no Java code at all.

I suspect android:keepScreenOn works by setting the FLAG_KEEP_SCREEN_ON on the window for you whenever the view is visible to the user. Anyway, this is handy to use if your need to keep the screen active is associated with a particular view in your app.

Posted in Android | Comments closed

Android WAKE_LOCK permission and VideoView

Our Android app has a need to keep the display alive, as the target audience is young children who may not be able to re-awaken a device that goes to sleep.

In Android, the general method to do this is to use the PowerManager class to create and manage a Wake Lock.  But this method has a few drawbacks:

  1. You must ensure you properly release the Wake Lock in your application, or else you can keep the device running all the time, even when your application is not foreground, and drain the battery dead.
  2. Your application must request the sandbox permission android.permission.WAKE_LOCK in the <uses-permssion> element of your AndroidManifest.xml file. In general, the more sandbox permissions your app requires, the more nervous customers get.

But if all you want to do with the wake lock is to ensure the screen remains on for as long as your app is in the foreground, there’s a better way to do it.  You can set a flag on your Activity’s window, telling the system to keep the screen alive:

getWindow().addFlags( WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON );

I first discovered this tip from the Google IO 2010 presentation Beginners Guide to Android. Besides being easier to code, one huge advantage of this approach is that you don’t have to worry about releasing the wake lock; Android will do it for you automatically when your window is no longer onscreen.

Up until recently, our app had requested the WAKE_LOCK permission in its manifest.  I recently learned that FLAG_KEEP_SCREEN_ON does not require you to declare the WAKE_LOCK permission, so I removed it.  In testing the app on all the devices we have at the office, everything seemed great. We shipped the change to customers, secure in the knowledge that we were Good Android Citizens for using as few permissions in our app as possible.

That’s when the support requests started rolling in:

On Sat, Nov 19, 2011 at 3:37 PM, A Customer <customer@gmail.com> wrote:
Hi,
Today I have bought your application.
It is nice.  However,  something wrong with the books.  I couldn’t open any book.  There always force closed after the short video.
Please let me know how to fix it.

Our application also uses Android’s VideoView class to display video.  On most devices, VideoView works just fine without any extra permissions required. But on some devices and ROMs (a Lenovo A1 tablet in the case of this customer), VideoView invisibly requests a Wake Lock.  An application on one of these devices which uses VideoView and doesn’t declare the WAKE_LOCK permission simply crashes at runtime.

So, the WAKE_LOCK permission goes back into our app.  And all of our customers will need to manually update on the next Market release, due to this undocumented requirement.

Truly, no good deed goes unpunished.

Posted in Android | Comments closed

Using Robolectric to Validate Android Internationalization

A while back, we at Zoodles made a proposal for adding a mechanism to Robolectric to automatically check for proper coding practices relating to internationalization.

Since nobody tried to stop us, we built the feature and merged it into the Robolectric master repository. We’re documenting it here for people who’d like to use it in their own projects.

What StrictI18n mode does

Robolectric’s Stricti18n mode is inspired by the “Strictmode” feature introduced into Android with the Gingerbread release. Stricti18n will validate your usage of the Android API as tests run, and will throw a runtime exception (specifically, com.xtremelabs.robolectric.util.I18nException) when your code invokes select Android API calls that accept bare text as an argument. For instance, the TextView widget has the following overloads of #setText():

public final void setText (int resid)
public final void setText (int resid, TextView.BufferType type)
public final void setText (char[] text, int start, int len)
public final void setText (CharSequence text)
public void setText (CharSequence text, TextView.BufferType type)

The first two versions of #setText() are safe for i18n purposes, since they use integer resource IDs into the Android strings.xml resource file. The final three are unsafe, as they take bare strings, such as string literals hardcoded into Java source files.

During a unit test scenario, if the application invokes any of the latter three API calls, Robolectric will throw an I18nException. Thus, your unit tests can also be used as a validation mechanism that you are properly externalizing your string resources.

The StrictI18n mode also validates text attributes defined in XML files. For instance, the following snippet from an XML layout file is not i18n-safe:

	<TextView
		android:id="@+id/mail_inbox_info"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="Your Inbox"/>

In this case, Robolectric would find that the android:text attribute is a bare string rather than a resource reference, and throw an I18nException as it inflates the layout. Robolectric performs this validation for layout, menu, and preference definition files.

How to Enable StrictI18n mode

By default, StrictI18n mode is off. You can enable or disable StrictI18n for your entire test suite, on a test case class basis, or on a test method basis.

Test Runner

The RobolectricTestRunner class has a switch to enable StrictIi18n mode globally. To enable i18n-strict mode globally, set the system property robolectric.strictI18n to true. This can be done via java system properties in either Ant or Maven.

Ant example:

	<junit>
		<!-- ... other junit options ... --> 
		<jvmarg value="-Drobolectric.strictI18n=true" />
	</junit>

For Maven, I won’t pretend I know the answer, since I haven’t authored Maven POMs in quite a while, but this Stack Overflow article looks like it has the secret sauce.

If you are subclassing RobolectricTestRunner, you can also override the following method to implement your own policy to turn StrictI18n on and off:

    protected boolean globalI18nStrictEnabled() {
    	return Boolean.valueOf(System.getProperty("robolectric.strictI18n"));
    }

Where I work at Zoodles, we simply hammer it to “on” in our test runner, for all of our development:

public class KidModeTestRunner extends RobolectricTestRunner {

	// ...

	@Override
	protected boolean globalI18nStrictEnabled() {
		return true;
	}
}

Annotations

Regardless of the global setting, you can use the following annotations to turn StrictI18n on and off for specific test cases:

com.xtremelabs.robolectric.annotation.EnableStrictI18n
com.xtremelabs.robolectric.annotation.DisableStrictI18n

This example enables StrictI18n for an entire test case class:

@RunWith(RobolectricTestRunner.class)
@EnableStrictI18n
public class SeekBarPreferenceTest {

	@Before
	public void setup() {
		// ...
	}

	@Test
	public void testConstructor() {
		// ...
	}

	@Test
	public void testOnCreateDialogView() {
		// ...
	}

}

This example disables StrictI18n for one specific test method:

	/**
	 * Show Link ID should display text link
	 */
	@Test
	@DisableStrictI18n
	public void testShowLinkIdTrue() throws Exception {
		mView.setItemId( 3 );
		mView.setShowLinkId( true );
		mView.updateDisplay();
		
		assertThat( mView.getLinkIdView().getVisibility(), equalTo( View.VISIBLE ) );
		assertThat( mView.getLinkIdView().getText().toString(), equalTo("3") );
	}

Annotations always override the global setting.

Developer Notes

Here’s some things we learned while developing this feature and using it against our application.

Formatted Strings

In our application code, we frequently came across the following type of use case:

	Toast.makeText( this, getString( R.string.native_game_blocked, app ), 
				 Toast.LENGTH_LONG ).show();

We’re generating a formatted string based upon a resource:

<string name="native_game_blocked">Blocked app \"%1$s\". To unblock, visit Apps in Parent Dashboard.</string>

and substituting in a piece of domain data (which is known to be I18n-safe).

We found ourselves disabling StrictI18n on a few too many tests due to these legitimate use cases of the Android APIs which take bare string arguments. In our app, this problem cropped up most often with the following UI elements:

  • Alert Dialogs (specifically with AlertDialog.Builder)
  • Button
  • CheckBox
  • TextView
  • Toast

To solve this problem, we created a package containing subclasses of these common Android UI classes. They provide I18n-safe alternatives to the bare-string methods that wrap the string formatting. Wherever we have need for this kind of specialized formatting, we use our custom classes in the XML layouts.

To prevent the StrictI18n mode from firing on these wrapper methods at test time, we created shadows for them that call the shadow implementations of the offending Android API methods.

If there is demand for these special I18n-safe classes, we’d consider making them available on github.

Caveats

There are some other caveats. For instance, if your test coverage is poor things can slip through. If that’s the case, you should work on the root issue, which is the lack of test coverage. It’s also possible that if Robolectric has not implemented a shadow for the API in question, your app will get a free pass. StrictI18n mode cannot detect calls to Android methods with no shadow implementation (the next section will make the reason for this limitation clear).

Developing Shadows with StrictI18n mode

If you are writing shadows, you can indicate that a given API call is not I18n-safe by passing the i18nSafe parameter to the @Implementation annotation, like this example from ShadowTextView:

    @Implementation(i18nSafe=false)
    public void setText(CharSequence text) {
        if (text == null) {
            text = "";
        }
        this.text = text;
    }

Robolectric will then intercept all calls to TextView#setText and throw exceptions if StrictI18n mode is enabled.

Posted in Android, Test driven | Comments closed

Displaying a frame-by-frame animation in Android

I originally wrote this answer in response to a Stack Overflow query. But the original question got downvoted and closed, for being too vague and ambiguous. So maybe I didn’t answer their question, but since it’s a decent answer here it is on my blog.

Question: How to display a frame-by-frame animation in Android? i.e., a sequence of frames, similar to an animated GIF.

Answer:

1) Prepare a series of PNG images with the individual frames of your animation.

2) Add them as assets to your project’s drawable folder, as you might do with any still bitmap image you’d use in your UI.

3) Prepare an animation-list XML animation. This will go into the anim folder of your project, and in this case the file is named g_tab_mail_new_anim_phone.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list 
    	xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
        <item android:drawable="@drawable/g_tab_mail_new_phone_default" android:duration="500" />
        <item android:drawable="@drawable/g_tab_mail_phone_default" android:duration="500" />
    </animation-list>

4) Set this animation as the background drawable of an ImageView (that is mMailTab in this example):

    mMailTab.setImageBitmap(null);
    mMailTab.setBackgroundResource( R.anim.g_tab_mail_new_anim_phone );

5) To make the animation start playing, you need to get a reference to the animation and tell it to start playing.

    final AnimationDrawable mailAnimation = (AnimationDrawable) mMailTab.getBackground();
    mMailTab.post(new Runnable() {
        public void run() {
            if ( mailAnimation != null ) mailAnimation.start();
	      }
    });

Here’s the Secret Sauce:

Note that this example does not directly call start() on the animation. Instead, it posts it into the message queue for the UI thread to act upon it at a later time. I’ve found this necessary if the animation is being started from your Activity’s onResume() method. If you’re not in the middle of onResume (say, you’re starting an animation in response to a button click or something) you should be able to simply call mailAnimation.start() directly.

Posted in Android | Comments closed

Using the Front-Facing Camera with Android Gingerbread

One welcome addition to the Android SDK in the Gingerbread (2.3) release is a standard API for accessing front-facing cameras on devices like the HTC EVO, Samsung Galaxy Tab, and now the new Google Nexus S.  With Froyo, we developers had a set of incompatible, poorly documented vendor-specific APIs to contend with – some I still haven’t gotten to work properly.

Opening the Camera

The code to access the front-facing camera under Gingerbread is pretty straightforward:

private Camera openFrontFacingCameraGingerbread() {
	int cameraCount = 0;
	Camera cam = null;
	Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
	cameraCount = Camera.getNumberOfCameras();
	for ( int camIdx = 0; camIdx < cameraCount; camIdx++ ) {
		Camera.getCameraInfo( camIdx, cameraInfo );
		if ( cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT  ) {
			try {
				cam = Camera.open( camIdx );
			} catch (RuntimeException e) {
				Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
			}
		}
	}
	
	return cam;
}

Remaining Compatible with Froyo

Of course, since this all uses Gingerbread API calls, you will run into problems if your code must also run on Froyo and earlier versions of the SDK.

Here’s a copy/paste code example that runs on any version of Android. It will access the front-facing camera, but fall back to the default (rear-facing) camera if no front-facing camera can be found.

This example achieves compatibility across Android releases by using the Java Reflection API to dynamically look up the appropriate API calls at runtime. If the appropriate API calls cannot be located, we are probably running on an older Android release, and fall back to the earlier APIs. It’s long and clunky, but that’s the price for doing things so indirectly.

/**
 * Open the camera.  First attempt to find and open the front-facing camera.
 * If that attempt fails, then fall back to whatever camera is available.
 *  
 * @return a Camera object
 */
private Camera openFrontFacingCamera() {
	Camera camera = null;
	
	// Look for front-facing camera, using the Gingerbread API.
	// Java reflection is used for backwards compatibility with pre-Gingerbread APIs.
	try {
		Class<?> cameraClass = Class.forName("android.hardware.Camera");
		Object cameraInfo = null;
		Field field = null;
		int cameraCount = 0;
		Method getNumberOfCamerasMethod = cameraClass.getMethod( "getNumberOfCameras" );
		if ( getNumberOfCamerasMethod != null ) {
			cameraCount = (Integer) getNumberOfCamerasMethod.invoke( null, (Object[]) null );
		}
		Class<?> cameraInfoClass = Class.forName("android.hardware.Camera$CameraInfo");
		if ( cameraInfoClass != null ) {
			cameraInfo = cameraInfoClass.newInstance();
		}
		if ( cameraInfo != null ) {
			field = cameraInfo.getClass().getField( "facing" );
		}
		Method getCameraInfoMethod = cameraClass.getMethod( "getCameraInfo", Integer.TYPE, cameraInfoClass );
		if ( getCameraInfoMethod != null && cameraInfoClass != null && field != null ) {
			for ( int camIdx = 0; camIdx < cameraCount; camIdx++ ) {
				getCameraInfoMethod.invoke( null, camIdx, cameraInfo );
				int facing = field.getInt( cameraInfo );
				if ( facing == 1 ) { // Camera.CameraInfo.CAMERA_FACING_FRONT 
					try {
						Method cameraOpenMethod = cameraClass.getMethod( "open", Integer.TYPE );
						if ( cameraOpenMethod != null ) {
							camera = (Camera) cameraOpenMethod.invoke( null, camIdx );
						}
					} catch (RuntimeException e) {
						Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
					}
				}
			}
		}
	}
	// Ignore the bevy of checked exceptions the Java Reflection API throws - if it fails, who cares.
	catch ( ClassNotFoundException e 		) {Log.e(TAG, "ClassNotFoundException" + e.getLocalizedMessage());}
	catch ( NoSuchMethodException e 		) {Log.e(TAG, "NoSuchMethodException" + e.getLocalizedMessage());}
	catch ( NoSuchFieldException e 			) {Log.e(TAG, "NoSuchFieldException" + e.getLocalizedMessage());}
	catch ( IllegalAccessException e 		) {Log.e(TAG, "IllegalAccessException" + e.getLocalizedMessage());}
	catch ( InvocationTargetException e 	) {Log.e(TAG, "InvocationTargetException" + e.getLocalizedMessage());}
	catch ( InstantiationException e 		) {Log.e(TAG, "InstantiationException" + e.getLocalizedMessage());}
	catch ( SecurityException e 			) {Log.e(TAG, "SecurityException" + e.getLocalizedMessage());}

	if ( camera == null ) {
		// Try using the pre-Gingerbread APIs to open the camera.
		try {
			camera = Camera.open();
		} catch (RuntimeException e) {
			Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
		}
	}

	return camera;
}

Manifest File

Finally, don’t forget to update your AndroidManifest.xml file with the appropriate declarations for the camera:

Permissions

	<uses-permission android:name="android.permission.CAMERA" />

Features

	<uses-feature android:name="android.hardware.camera"	  		android:required="false"/>
	<uses-feature android:name="android.hardware.camera.front" 		android:required="false"/>

Of course, you should adjust the android:required attributes as necessary for your app.

Posted in Android | Comments closed

Robolectric: Building your test project with Ant

I’m sharing some lessons learned from setting up the Ant build.xml file for my Robolectric test project.  Hopefully they will save you the day or so of frustration I spent tracking down these issues.

Running JUnit 4 from Ant

The first challenge is getting Ant to properly run JUnit 4.  I’m using Ant 1.8.1, and like modern versions of Ant it has a junit task built in.  If you just try to run your Robolectric tests with the junit task out of the box, you’ll get an error something like the following:

BUILD FAILED
/Path/to/my/test/project/build.xml:44: java.lang.RuntimeException: Stub!
	at junit.framework.TestResult.(TestResult.java:4)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:317)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.executeInVM(JUnitTask.java:1353)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.execute(JUnitTask.java:808)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.executeOrQueue(JUnitTask.java:1808)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.execute(JUnitTask.java:760)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.Target.execute(Target.java:390)
	at org.apache.tools.ant.Target.performTasks(Target.java:411)
	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1397)
	at org.apache.tools.ant.Project.executeTarget(Project.java:1366)
	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
	at org.apache.tools.ant.Project.executeTargets(Project.java:1249)
	at org.apache.tools.ant.Main.runBuild(Main.java:801)
	at org.apache.tools.ant.Main.startAnt(Main.java:218)
	at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
	at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)

Total time: 0 seconds

The key problem here is that Ant’s junit task is using JUnit 3.8 by default.  (The class junit.framework.TestResult is the dead giveaway, as it does not exist in JUnit 4.)

JUnit 3.x has no support for test annotations. It ignores the RunWith annotations on the test case classes, the Robolectric test runner is not invoked, and so the tests fail.

After consulting the Ant JUnit documentation on the Apache website, you’ll learn that in Ant 1.7 or later, you can specify a classpath to the junit task, including the jar file for JUnit 4. In our case, we had a copy of junit-4.8.2.jar sitting in the ${libs.dir} folder of our project:

	<path id="junit_classpath">
		<pathelement path="${build.dir}"/>
		<fileset dir="${libs.dir}" includes="*.jar"/>
		<fileset dir="${external.libs.dir}" includes="*.jar"/>
		<fileset dir="../MyMainProject/libs" includes="*.jar"/>
	</path>

But if you run the above, you’ll still get an error.  What gives?

Here’s the secret.  Place the entry for junit.jar ahead of android.jar in the classpath, and it will all work fine:

	<path id="junit_classpath">

		<!-- NOTE: junit.jar must come before android.jar -->
		<pathelement location="${libs.dir}/junit-4.8.2.jar"/>

		<pathelement path="${build.dir}"/>
		<fileset dir="${libs.dir}" includes="*.jar"/>
		<fileset dir="${external.libs.dir}" includes="*.jar"/>
		<fileset dir="../MyMainProject/libs" includes="*.jar"/>
	</path>

Cleaning up the Robolectric cache

Not too long after running Robolectric tests, they started failing mysteriously, both on my development system and on the CI server with error stacktraces like the following:

java.lang.ClassFormatError: Illegal UTF8 string in constant pool in class file android/widget/RemoteViews
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:466)
	at com.xtremelabs.robolectric.RobolectricClassLoader.findClass(RobolectricClassLoader.java:58)
	at javassist.Loader.loadClass(Loader.java:311)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
	at com.xtremelabs.robolectric.RobolectricClassLoader.loadClass(RobolectricClassLoader.java:37)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:247)
	at java.lang.Class.initAnnotationsIfNecessary(Class.java:3070)
	at java.lang.Class.getAnnotation(Class.java:3029)
	at com.xtremelabs.robolectric.Robolectric.bindShadowClass(Robolectric.java:60)
	at com.xtremelabs.robolectric.Robolectric.bindShadowClasses(Robolectric.java:70)
	at com.xtremelabs.robolectric.Robolectric.bindDefaultShadowClasses(Robolectric.java:65)
	at com.xtremelabs.robolectric.LoadableHelperImpl.setupApplicationState(LoadableHelperImpl.java:22)
	at com.xtremelabs.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:136)
	at com.xtremelabs.robolectric.RobolectricTestRunner.methodBlock(RobolectricTestRunner.java:110)

No amount of cleaning and rebuilding would make the tests run properly.

After much poking around, I discovered the cause for these errors is a stale Robolectric class cache jar file.  I updated the clean task in my project to remove the cache jar:

	<target name="clean" description="clean up" >
		<delete dir="${build.dir}"/>
		<delete dir="${test.output.dir}"/>
		<delete file="${basedir}/tmp/cached-robolectric-classes.jar"/>
	</target>

And this now gives me repeatable, successful builds.

I hope.

Posted in Android, Test driven | Comments closed

What Eclipse files to check in with a new project

This info is available elsewhere on the net, but I am including it here because I have to look it up every time and I’m tired of it.

Check in

  • .project
  • .classpath
  • .settings Check in these files if you wish to share with the rest of the team:
    • .settings/org.eclipse.jdt.ui.prefs – it contains the settings for the import ordering
    • .settings/org.eclipse.jdt.core.prefs – it contains the settings for the compiler version

Do not check in

  • .metadata It contains a bunch of state information for your Eclipse workspace, which is changing all the time.

When setting up the project on the new machine use File > Import … > General > Existing Project Into Workspace.

References

http://stackoverflow.com/questions/445187/to-check-in-or-not-check-in-the-entire-eclipse-project

http://www.alittlemadness.com/2010/05/31/setting-up-an-android-project-build/

Posted in Eclipse | Comments closed