Testing Asynchronous Tasks on Android

Recently, at Sixt we have been migrating our development environment from Eclipse to Android Studio. This has mean we have also moved to the new build system, Gradle, and applying TDD and CI to our software development process. This is not the place to discuss the benefits of applying CI to a software development plan, but to talk about a problem arising when testing tasks running on different threads than the UI in Android.

 

A test in Android is (broad definition) an extension of a JUnit Suitcase. They do include setUp() and tearDown() for initialization/closing the tests, and infers using reflection the different test methods (starting with JUnit 4 we can use annotations to specify the priority and execution of all the tests). A typical test structure will look like:

public class MyManagerTest extends ActivityTestCase {

	public MyManagerTest(String name) {
		super(name);
	}

	protected void setUp() throws Exception {
		super.setUp();
	}

	protected void tearDown() throws Exception {
		super.tearDown();
	}

	public void testDummyTest() {
		fail("Failing test");
	}

}

This is a very obvious instance: in a practical case we would like to test things such as HTTP requests, SQL storage, etc. In Sixt we follow a Manager/Model approach: each Model contains the representation of an Entity (a Car, a User…) and each Manager groups a set of functionality using different models (for example, our LoginManager might require of models Users to interact with them). Most our managers perform HTTP  requests intensively in order to retrieve data from our backend. As an example, we would perform the login of a user using the following code:

 

	mLoginManager.performLoginWithUsername("username", "password", new OnLoginListener() {
		@Override
		public void onFailure(Throwable throwable) {
			fail();
		}

		Override
		public void onSuccess(User customer) {
		//..
		}
	});

When it comes to apply this to our own test suitcase, we just make the process fail() when the result does not work as we were expecting. We can see why in the method onFailure() we call to fail().

However, even if I was using a wrong username the test was still passing. Wondering around, seems that the test executed the code sequentially, and did not wait until the result of the callbacks was back. This is certainly a bad approach, since a modern application do intense usage of asynchronous tasks and callback methods to retrieve data from a backend!. Tried applying the @UiThreadTest bust still didn’t work.

I found the following working method. I simply use CountDownLatch signal objects to implement the wait-notify (you can use synchronized(lock){… lock.notify();}, however this results in ugly code) mechanism. The previous code will look like follows:

	final CountDownLatch signal = new CountDownLatch(1);
	mLoginManager.performLoginWithUsername("username", "password", new OnLoginListener() {
		@Override
		public void onFailure(Throwable throwable) {
			fail();
			signal.countDown();
		}

		Override
		public void onSuccess(User customer) {
			signal.countDown();
		}
	});
	signal.await();

 

A high-entropy randomness generator

 

This cartoon of Dilbert always has always fascinated me. You can never be sure about randomness, since the concept itself of randomness provides uncertainty to the process. A few years ago, I even wrote a post on how to achieve randomness using deterministic methods. Nowadays, entropy can always be improved to obtain a more accurate (in this case would be more appropriate to say “less accurate” instead) result.  This can lead into many philosophical discussions, which are not my purpose.

The traditional approach has been to take contextual information (such as the UNIX time) to create a seed for the algorithm and give more uncertainty to the process. This might be sufficient for 99% of our purposes, but leads to more complex problems: For instance, is easy to determine when a user logged into a system, and if at this time a random number is generated to, at the same time, generate some cryptographic keys, is easy to establish an interval when the user was logged (and therefore being closer to the seed of the random algorithm). Is still difficult to determine accurately the exact time, but definitely not impossible: systems of huge relevance face this problem daily.

Recently a publish in the Android Market Chinese Radicals, a program to learn Chinese. Since I need to choose randomly the Chinese radicals for the program, I decided to use it as a testbed to extend my experiment from 3 years ago. The approach is using some “contextualization” of the seed, and combining it with a probability density function. The explanation can get really complex, but I’ll try to summarize:

  1. At a certain point of execution, I categorize the accesible memory of the thread where the software is running (size and number of memory blocks). This information is stored and modeled for the density function.
  2. Afterwards, I take the UNIX time of the system. I apply a probability distribution to the model saved in the first step, and then combine it with this second point. I store the current time, and apply a first pass.
  3. When the generation of the random number is finished, I determine the difference between that time and the time I stored in the step two. Since the memory information saved in the point 1 (the entropy of the system) might differ, this time will likely be different. Then I apply a second pass to generate, with more certainty, the random number.

 

I have released this generator as a Java .jar. You can include in any Java project (Swing, Blackberry, Android, etc). You can download it from here. It works as follows:

  1. Import the jar
  2. Import the class com.randomizator.Randomizator, and create an object Randomizator by using Randomizar myObject = new Randomizator();
  3. Using randomizator.getInt( interval ) will return you a random number between 0 and the number provided.

So far only the generation of integer values is supported. Please, check it out and let me know what you think.

 

Using PHP on server side to generate JSON

Recently, I publish one application into the Android Market that tries to predict when Spain will default. The application uses the data provided by my colleague Juan Carlos Barba from his server. There are basically a set of levels pointing out the seriousness of the Spanish level of CDS and Spread of the debt. The model establishes 5 different levels of alert (or how he called them, DefCon). My implementation customized the data to visualize into the Android Platform.

Firstly, I needed to access his database into the server, which was a slow task due to the nature of the server (a personal computer with a normal DSL connection). My idea was to rely this task into something that could avoid overloading the server, and then I thought about everything that happens now with all the client / server application. Why not using a PHP file to generate JSON with the information I needed?

Since I do not have access to Juan Carlos’ server, I decided to do it on my own server. I created some PHP files that query the server, and give me the information in JSON format

 

Now the data has to be requested and handled from the Android side:

 
private void initPHP() {
		//http post
		 String result = "";
		  InputStream is = null ;
		 try{
			 DefaultHttpClient httpclient = new DefaultHttpClient();
		         HttpPost httppost = new HttpPost("http://www.neo-tech.es/defcon/cds.php5");
		         HttpResponse response = httpclient.execute(httppost);
		         HttpEntity entity = response.getEntity();
		         is = entity.getContent();
		 } catch(Exception e) {
		         Log.e("log_tag", "Error in http connection "+e.toString());
		 }
		 //convert response to string
		 try{
		         BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);
		         StringBuilder sb = new StringBuilder();
		         String line = null;
		         while ((line = reader.readLine()) != null) {
		                 sb.append(line + "\n");
		         }
		         is.close();
		  
		         result=sb.toString();
		 }catch(Exception e){
		         Log.e("log_tag", "Error converting result "+e.toString());
		 }
		  
		 //parse json data
		 try{
		         JSONArray jArray = new JSONArray(result);
		         int lastDay = 0;
		         for(int i=0;i

The code can be improved to handle authentication, HTTPS, or do more complex work in general. In a project at work we used authentication based on a pair of generated keys, but a simple method based on a known keyword is enough.

Language Assistant program for Android

For a long time, I used to manage the different language files in Android manually. This is an incredible boring task when our program is growing and getting more complex, since the only way to compare tokens is doing it one by one, and is an error-prone task.

This program is an extension to a similar program developed by my colleague Eugenio Marchiori at the e-UCM group. The program compares all the tokens between two different languages, assigning different codes depending if the token is missing in one language, or it is has been created. The task of creating new language files is also very easy, since they can be created using a full version as reference.

The program can be downloaded from this link. In the first screen, the parent folder of an Android project has to be selected. After that, you just can edit your language files!

UPDATE: Now the application has been released as a GPL application. You can download it from the Google Code repository.

Language Assistant for Android

Cursos gratuitos de Sun

Si eres estudiante matriculado en la UCM, ahora podrás tener acceso gratuito a los cursos de Sun Learning connection. La mayoría de estos cursos involucran temáticas relacionadas con Solaris y Java.

Es necesario aportar estos datos cuando se realiza el registro (company name y company ID):

Company Name: SAI-Universidad Complutense de Madrid

Company ID: CUS-0000096750

Aquí una pequeña muestra de lo que estos cursos ofrecen. Incluso Sun ofrece certificados por aquellos cursos que se han conseguido finalizar con éxito, como se puede ver en el User Guide (queda por ver, no obstante, cual es el valor real, o la valoración que puede llegar a tener, un certificado que se descarga y se imprime).

Continue reading