First Android App

After mentioning my new toy a couple of posts ago I mentioned I was hoping to do a bit of Android development.

I’ve been doing a bit of Android work as part of my new job (I recently joined a very cool team at work) making some existing Java code run, but this is my first real application.

I had left the TV on and gone to the office one day last week and while it did not permanent damage, there was a slight bit of ghosting from the MythTV menu for a day or 2 afterwards. I already have my TV hooked up a couple of topic on my home MQTT broker, so I though that running up a simple Android Widget to show the state would be a good starting point.

MQTT Topic Tree
MQTT Topic Tree

The TV/Status topic updates every 30 seconds and currently shows either off or a string like on:RGB:6 which is made up of state, input and volume.

The first task is to create a Android Service that will subscribe to this topic and watch for changes. The standard IA92 MQTT drivers can be used with the Android SDK to get access to the broker, so the connect code is very similar to the code used in my Twitter2MQTT bridge except the id for the client is generated from the phones unique id.

private String android_id =Secure.getString(this.getContentResolver(),Secure.ANDROID_ID);

private boolean connect() {
  try {
    client = (MqttClient) MqttClient.createMqttClient("tcp://tiefighter.loc:1883", null);
    client.registerSimpleHandler(new MessageHandler());
    client.connect("droid-"+android_id, true, (short) 240);
    String topics[] = {"TV/Status"};
    int qos[] = {1};
    client.subscribe(topics, qos);
    return true;
  } catch (MqttException e) {
    e.printStackTrace();
    return false;
  }
}

The MessageHandler is an inner class and handles both incoming messages and reconnection using the following 2 methods.

public void publishArrived(String topic, byte[] payload, int qos, boolean retained) throws Exception {
	String message = new String(payload);
	// This is to allow access to the notification service from a none 	
	if (Looper.myLooper() == null) {
		Looper.prepare();
	}
			
	RemoteViews updateViews = new RemoteViews(TVLongService.this.getPackageName(), R.layout.main);
			
	String toastMsg = "";
	String toastHead = "";
	int icon = 0;
	boolean alert = false;

	if (message.equals("off")) {
		if (TVWidget.on) {
			toastMsg = "TV now OFF";
			toastHead = "TV OFF";
			icon = R.drawable.tv_off;
			alert = true;
			TVWidget.on = false;
		}
	} else {
		if (!TVWidget.on) {
			toastMsg = "TV now ON";
			toastHead = "TV ON";
			icon = R.drawable.tv_on;
			alert = true;
			TVWidget.on = true;
		}
	}

	if (alert) {
		Intent intent = new Intent();
		PendingIntent contentIntent = PendingIntent.getActivity(TVLongService.this, 0, intent, 0);
		NotificationManager notificationManager = (NotificationManager) TVLongService.this.getSystemService(Context.NOTIFICATION_SERVICE);
		Notification notification = new Notification(icon, toastHead, System.currentTimeMillis());
		notification.setLatestEventInfo(TVLongService.this, "TV Monitor", toastMsg, contentIntent);
		notificationManager.notify(1, notification);
		updateViews.setImageViewResource(R.id.img, icon);
	}

	ComponentName componentName = new ComponentName(TVLongService.this, TVWidget.class);
	AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(TVLongService.this);
	appWidgetManager.updateAppWidget(componentName, updateViews);
}

TVWidget
The MessageHandler onMessage method fires when a message is posted to the TV/Status topic and then updates the widget Icon from tv_on to tv_off and then triggers a notification pop-up if the state has changed since the previous state.

The connectionLost method fires up a background thread to try and reconnect to the broker every 10 seconds.
TVWidget_on

TVWidget_toast

public void connectionLost() throws Exception {
	client = null;
	Log.v("TVMonitor","connection dropped");
	Thread t = new Thread(new Runnable() {
		
		@Override
		public void run() {
			do {//pause for 5 seconds and try again;
				Log.v("TVMonitor","sleeping for 10 seconds before trying to reconnect");
				try {
					Thread.sleep(10 * 1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} while (!connect());
			System.err.println("reconnected");
		}
	});			
}

Next Steps

  • Survive network changes

    At the moment the code does not handle moving from WIFI to 3G networking all that well, there are collection of BroadCast future PendingIntents that should signal changes in network state.

  • Geo-Fencing

    I don’t really need to know that the TV is on while I’m at home, so I’m planning on adding a filter so notifications are only fired when I’m outside say 200m of home

  • MythTV

    May be add some indication as to what channel is currently being watched and what the upcoming recordings may be

13 thoughts on “First Android App”

  1. Hi Ben, would it be OK to borrow / reuse your diagrams within my LinuxConf AU pitch on MQTT? With links etc back to your post, of course :-)

  2. Hi Ben, where can I download Telemetry and how much is it going to cost me? Do I need to pay the licencing fee?

    Regards,
    Mike

    1. Mike,

      Have a look at http://mqtt.org/software. It has links to all the different MQTT client and server implementations that are available.

      There are selection of both commercial and opensource implementations to suit all different needs.

  3. Thanks for the quick response. I am looking to develop and Android App for a college final year project. This will relatively small and simple(I hope). What would you recommend that I use can I get something opensource to serve my needs.
    Cheers,
    Mike

    1. Mike

      For the broker side you have a choice of rsmb from alphaworks (double check the license, I think you will be ok for educational use, but I’m not a lawyer) or mosquito the open source implementation.

      For the client side your only real choice is going to be the IA92 Java package from IBM, again you’ll have to check the license.

    1. Craig,

      No, but nearly all of code is actually in the post and to be honest there are better ways to use MQTT on android than the code in this project. Dale Lane has a great post that explains in great detail how to do things properly and has sample code.

  4. Thanks for the quick replay. He didn’t post his code, when contacted he says just copy and paste. I have to figure the project structure and where to paste, he doesn’t mention file names though. I haven’t done any android stuff for a couple years, need to brush up. I got python, php, arduino running with mosquitto in minutes, android might take a 2 to 3 hours. Our solar production prototype field units and test equipment is mqtt messaging now around 80K messages/day.

  5. Hi Guys,

    I am pretty new to this field of MQTT.

    Taking some examples around the web I tried to consume or subscribe at one of the topics created at http://mqtt.io/

    However when I tried to connect to the message broker using connecting string as
    client = (MqttClient) MqttClient.createMqttClient(“tcp://q.m2m.io:8083″, null);

    I get a return error type as

    CONNACK not received exception

    1. I’ve not used the m2m.io servers, but I would guess that port 8083 is only listening for MQTT over Websockets not pure MQTT connections.

Leave a Reply to hardillb Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>