Stupid mistakes devs make, part I: Taking app messages at face value

This is a new series about programming blunders I make. Stuff that keeps me looking for solutions in all the wrong places while the answer most often is glaringly simple. If only I knew that right away!

I am sorry for the generalization in the headline – of course it’s only me doing stupid stuff like that ;-)

Mistake of the day

Yesterday I was happily coding the sharing action for my upcoming app. This particular ShareActionProvider of the app lets users share a picture of their progress with keeping bad habits in check. I create an image and make it available to other apps via a content:// Uri. Nothing spectacular about that.

You might know that the Email app asks your ContentProvider for the display name and the file size of the shared image. The image in question is about 20K in size. That’s far from being an overly big picture. Nevertheless I got the message that the attachment was too large:

Toast showing that the attachment was too large

Toast showing that the attachment was too large

This left me wondering, what might possibly be wrong. I looked at the log messages. Check. I looked at the size of the stored image. Check. I debugged into my content provider to see that it reported the correct file size. Check. Starting to go out of ideas I even adb pulled the file and opened it in an image viewer. Check – it indeed was an image. I had another look at logcat. Check. All fine. So what the heck… My curse level had increased considerably! Never a good sign.

But wait a moment. One of those checks above was not correct. Actually two of those were not correct. And – to be honest – just assuming that the message of the Email app was correct, probably was the first mistake. It totally misled me – and even worse: I let it do that.

Finally I looked a bit more carefully. It turns out that I stopped debugging my content provider too early. And that I grepped logcat too rigorously.

My content provider crashed shortly after the line where I stopped debugging, assuming everything to be perfectly fine. This assumption proved to be very wrong, since my code ran into a ClassCastException :-(

And I didn’t see it in logcat because I renamed my package a few days ago, but didn’t rename my logging tag. The tag was the final part of the old app package name. And I grepped only for this tag – which proved to be very stupid! With this clever way of grepping any hints of stacktraces were gone.

Finally: I didn’t notice this problem in any tests, because I do not work test first and simply had no tests for the sharing part of my provider.

BTW: I do neither get the “File too large to attach” message on an old API level 8 device, nor on my GNex or my N5. Alas I had my Nexus 7 used for testing, which I update rarely since it’s a testing device only. The Email app seems to have been fixed. So with any of my other testing devices, I probably wouldn’t have had the same problems. It was just one of those days :-(

Lessons learned

Actually running into stuff like this is not all bad. Okay, granted: It is. I wasted too much time with it. But the good part is, that it’s just another lesson along the way. And a lesson I probably won’t forget that soon.

For this day my takeaways were:

  • Do not trust messages of other apps
  • Do not rename packages without renaming logcat tags as well
  • Stop being so sloppy with your tests

That’s it for today. The next post in this series will have the name “Be careful with that package name, Eugene”. Obviously it nicely fits the scheme of this post since it’s just another package name mishap.

Have you experienced anything like that? If so, please let us know in the comments. Don’t let me be the only fool around :-)

An XMPP Server for Google Cloud Messaging

In this post I am going to write about the server-side of upstream messages with Google Cloud Messaging. This is the second part of my three-part series on this topic. If you haven’t read the first part about the flow of events and the Android implementation of upstream messaging, please read that one first. The first sections of that post are important to understand the big picture of upstream messaging and the role of the server within it.

Sample project

I have created a sample project for the server side of upstream messaging with Google Cloud Messaging. Please note that this is a sample. It’s not suitable for production!

Permanent connection and XMPP

Just recall the flow of events, described in detail in my first post:

The communication model of Google Cloud Messaging with the new Cloud Connection Server

The communication model of Google Cloud Messaging with the new GCM Cloud Connection Server

For this flow to work, Google must contact your server whenever the user sends a message from his device upstream to Google’s cloud. There are many models of how to do that. The one chosen by Google is to require a permanent connection between your backend and one of Google’s endpoints.

That’s where XMPP comes into play. Google has chosen XMPP as the protocol of choice for communicating between its servers and your server. Google named its XMPP endpoint “GCM Cloud Connection Server” or CCS for short. XMPP is an XML-based protocol that was created for instant messaging (also known under it’s original name Jabber). You can read more about XMPP on Wikipedia.

Server side code

In the previous post about upstream messaging you have seen that the Android side of GCM messaging is as simple as it can get.

The server side though is another matter altogether and got more complicated with the new solution.

First of all you’re most likely not as familiar with XMPP as you are with HTTP. And you’re not alone with it. HTTP is probably the most used application layer protocol. Thus the online knowledge base for HTTP is huge. Less so for XMPP. You probably have to search longer for solutions when hitting a stumbling block with XMPP.

This situation also applies to libraries. While there is an abundance of HTTP libraries, there are way less for XMPP. For Java I have found only one library that is still actively maintained: The Smack library, which Google also uses in its sample code.

Luckily Google has a very detailed description of all the message types exchanged between your server and Google’s cloud. And since XMPP is text-based you could build a client on your own – no matter which language you use. Nevertheless I recommend to use a library for this – after all they not only ease your life but are also more heavily tested. It’s likely that others already have found a solution for a problem that would otherwise bite you in production when writing your own code.

I have taken Google’s sample code for XMPP and extended it to be more flexible and suit my needs. This code requires the Smack and the json-simple libraries. To repeat: The demo is there just to get you up and running, so that you can easily test the upstream messaging model and your Android code. It’s still very basic and rough!

Logging messages

When setting up the connection using Smack’s XMPPConnection, you can configure it to open a Swing window displaying all incoming and outgoing messages:

config.setDebuggerEnabled(mDebuggable);

I set the flag to true when using the main() method of CcsClient. That obviously wouldn’t work too well on a server so I made this configurable. From within my web project I set this flag to false.

There is another flag that configures if Smack logs every message:

XMPPConnection.DEBUG_ENABLED = true;

Within the sample code I simply set this to true to see every message. Very handy for finding problems during development and appropriate for this demo project.

Implementing a server

These are the things you have to take care of:

  • Establish the connection
  • Authenticate your server app
  • Receive messages from Google’s cloud
  • Send messages to Google’s cloud
  • Acknowledge messages
  • Deal with problems

Since all message types are described in detail on Google’s Cloud Connection Server page, you can use whatever solution you like. The following code samples are in Java and make use of the Smack library. While some stuff is from Google’s sample code, some contains additions and abstractions around that sample code.

The most important class is CcsClient. This class is responsible for logging in to the server, sending messages to Google’s Cloud, receiving incoming messages and handling ACKs and NACKs correctly.

Connect to the GCM Cloud Connection Server

For the permanent connection you open a TLS secured connection to gcm.googleapis.com at port 5235.

Within CcsClient the method connect() handles this. It needs a ConnectionConfiguration object.

Here’s how to set up the ConnectionConfiguration:

config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
config.setSecurityMode(SecurityMode.required);
config.setReconnectionAllowed(true);
config.setRosterLoadedAtLogin(false);
config.setSendPresence(false);
config.setSocketFactory(SSLSocketFactory.getDefault());

In the first line you specify which server and which port to use. As mentioned these have to be gcm.googleapis.com and 5235 respectively. And you have to ensure to use Transport Layer Security (TLS). That’s why you have to set the SSLSocketFactory.

Afterwards you can create a Connection object and use it to establish the connection to Google’s servers:

Connection connection = new XMPPConnection(config);
connection.connect();

Authenticate your server app

Google needs to ensure that you are allowed to send messages via Google Cloud Messaging – and that you are allowed to send them to the clients you are addressing. For this Google uses a project id and an API key specific for that Google Cloud project.

I have detailed in my previous post about upstream messaging how to create a project and how to generate a server API key for that project.

With XMPP you do not send the API key with every request. Instead you authenticate your server app directly after establishing the connection.

In Java just use the Connection object you created in the previous step to log in:

connection.login(mProjectId + "@gcm.googleapis.com", mApiKey);

Obviously you have to use the values created on Google’s Cloud Console for mProjectId and mApiKey. You either pass them as arguments to the main() method of CcsClient or you call prepareClient() with the correct values – which I do from within my web project.

After logging in, you can send and receive messages.

Message formats

Before I will cover how to send or receive messages, I’m going to show you some typical messages sent either from your server or back to your server.

Incoming upstream messages

The following is a message as it shows up on your server when a user clicks “Register” in the Android client sample:

<message 
      to="projectId@gcm.googleapis.com" 
      from="devices@gcm.googleapis.com">
   <gcm xmlns="google:mobile:data">
      {
      "category":"com.grokkingandroid.sampleapp.samples.gcm",
      "data":
         {
         "action":
            "com.grokkingandroid.sampleapp.samples.gcm.REGISTER",
         "account":"info@openminds.de"
         },
      "message_id":"20",
      "from":"someRegistrationId"
      }
   </gcm>
</message>

This message is no different from any other message sent from an Android device. It is obvious that the message consists of an outer XML part and an inner JSON part. You can safely ignore the XML part. It’s always the same and is only used since XMPP is an XML based protocol. What’s important is the JSON part. The JSON object contains all the attributes you need to react appropriately to incoming messages.

All upstream messages contain the following attributes:

The attributes of a received GCM upstream message
Attribute Meaning
category Package name of the sending app
data The payload of your app
message_id A unique id you need later on to acknowledge the message
from The registration id of the device from which the message was sent

Obviously only your apps can send data to your server. But you can use the same GCM server for multiple apps. That’s why the category attribute is needed.

The data attribute is where you can put all the stuff, that you want to transmit to your server. The value of the data attribute is a JSON object itself.

The registration id is sent with every message within the from attribute. It’s a very lengthy string which you must use to map the data to the correct user.

ACK messages

The next section explains what’s up with the ACK and NACK messages. For now, you just need to know what those messages look like.

An ACK message is the simpler of both and always looks the same:

<message>
   <gcm xmlns="google:mobile:data">
      {
      "message_id":"m-8238983812089683316",
      "message_type":"ack",
      "from":"someRegistrationId"
      }
   </gcm>
</message>
The attributes of an ACK message
Attribute Meaning
from The registration id to which the message was sent
message_id The id of the message, that is acknowledged
message_type ACK or NACK – for ACK messages obviously always “ack

Incoming NACK messages

NACK messages come in two types. A stanza message always indicates a malformed message on your side. Stanza is the weird name used in the XMPP specification for the different kinds of XML messages that XMPP supports. Any other erroneous condition is handled by the second type of NACK messages.

Let me show you a stanza message first:

<message 
      id="iUB3B-2" 
      to="someProjectId@gcm.googleapis.com" 
      type="error">
   <error 
         code="400" 
         type="MODIFY">
      <bad-request 
            xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
      <text 
            xml:lang="en" 
            xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
            InvalidJson: JSON_PARSING_ERROR
                  : Missing Required Field: message_id
      </text>
   </error>
   <gcm xmlns="google:mobile:data">
      {
      "to":"someRegId",
      "delay_while_idle":true,
      "data":
         {
         "message":
               "Simple sample sessage"
         },
      "time_to_live":120000
      }
   </gcm>
</message>

The error element of the XML message contains the description of what went wrong. And the gcm element contains the complete message you have sent to the server. The descriptive error message together with the full message causing the problem makes it really simple to understand what went wrong. In this case, the message_id is missing. I won’t go into detail for this type. You get those messages only, if you do not provide all mandatory attributes.

Stanza error messages should only happen while developing your app. What might follow later on are other problem types. Here is a sample message for other failure situations:

<message>
   <gcm xmlns="google:mobile:data">
      {
      "message_id":"m-4370299872608467243",
      "from":"invalidRegId",
      "error":"BAD_REGISTRATION",
      "message_type":"nack"
      }
   </gcm>
</message>

In this case the registration id you sent to Google’s server is invalid. Note: You will also get NACK messages for as long as your sign-up form hasn’t been processed by Google.


The attributes of a NACK message
Attribute Meaning
error A short error message
from The registration id to which the message was sent
message_id The id of the message, that is acknowledged
message_type ACK or NACK – for NACK messages obviously always “nack

Outgoing messages to devices

The final message type is a message from your server to an Android device:

<message id="4icfN-5">
   <gcm xmlns="google:mobile:data">
      {
      "to":"someRegistrationId",
      "delay_while_idle":true,
      "data":
         {
         "message":"Test message to a registered device"
         },
      "message_id":"m-15",
      "time_to_live":10000
      }
   </gcm>
</message>

Some of the attributes for sending messages via the Cloud Connection Server are the same as with messages via Google’s HTTP server. Others though are new and still others are missing. The following table shows a list of all possible attributes for sending XMPP messages to a device.

The attributes of a push message
Attribute Meaning Mandatory
collapse_key A key indicating that only the last message of this type should be sent to a device when it comes online again No
data The payload of your app No
delay_while_idle A flag indicating that messages should be kept on Google’s server if the device is inactive No
message_id A unique id you need later when dealing with ACK and NACK messages Yes
time_to_live The amount of time for which Google should keep the message around if the device is offline No
to The registration id of the recipient Yes

If you have used GCM in the past you will notice the to attribute. That’s the XMPP replacement for registration_ids. And in contrast to registration_ids you can send a message to only one user. Which means that for a broadcast you have to iterate over all registration ids. See Google’s documentation for details.

The delay_while_idle attribute tells Google that it should not send a message when the client device is not active. A value of true means that messages are kept on Google’s server until the device is active again.

The collapse_key probably needs some more explanation. If a device is offline you do not want it to get swamped with messages when it goes online again. Instead you can use the attribute collapse_key to ensure that only the last message for this key gets delivered to the app. But note: You can use only four collapse keys at the same time. The collapse_key applies to messages not delivered right away because of an delay_while_idle flag, but also to messages than cannot be delivered because the device isn’t connected at all.

You might have noticed that the data attribute is optional. Now at first this might sound like a pointless exercise. Why send a message without any data in it? But it depends on the purpose of the message. You can use a GCM message as a tickle. To simply notify your app, that there’s new data on the server to download. Unless the app can download different types of data, an empty message would be enough. When such a message arrives, your app would try to contact your server and download what it has to know.

If you do not set a time_to_live value, the default is used. The default currently is four weeks.

Message acknowledgements

The GCM Cloud Connection Server expects your server to acknowledge each and every method it sends to you. Google states explicitly that you should never send a NACK!

Always having to acknowledge messages means you should be able to deal with those messages. Take care of exceptional conditions, that might come up at your end. Google will resend messages for which you fail to send an acknowledgement. So not acknowledging puts unnecessary burden on your server.

Here’s what Google expects your server to adhere to:

For each device message your app server receives from CCS, it needs to send an ACK message. It never needs to send a NACK message. If you don’t send an ACK for a message, CCS will just resend it.

Source: https://developer.android.com/google/gcm/ccs.html

Google sends back ACK or NACK messages for every message your backend sends towards Google’s cloud. Google obviously is allowed to send NACKs. A NACK coming from Google means that you did something wrong – most of the time at least. For example you will get NACK messages for trying to send messages to registration ids that aren’t valid anymore.

Google will also send NACKs if the service is down or in case an “Internal Server Error” occurred. In the first case you should simply queue the message to resend it sometime later. In the second case though, you are a bit on your own. Most likely resending should be fine since most other cases are handled with other exception codes. So most likely it’s a problem on Google’s end – but you cannot know for sure. Maybe the problem is caused by the content of your message after all. It might be a good idea to add an internal retry counter which you decrease with every transmission. At the very least log those cases and have a look at them.

Receive messages from Google’s cloud

To handle incoming messages with Smack, you first have to register a PacketListener object with the Connection you created in the first step above. This object is responsible for all incoming traffic. See this slightly adapted version of Google’s code:

connection.addPacketListener(new PacketListener() {
   @Override
   public void processPacket(Packet packet) {
      Message incomingMessage = (Message) packet;
      GcmPacketExtension gcmPacket =
            (GcmPacketExtension)incomingMessage
                  .getExtension(GCM_NAMESPACE);
      String json = gcmPacket.getJson();
      try {
         Map jsonMap =
               (Map)JSONValue.parseWithException(json);
         
         handleMessage(jsonMap);
      } catch (ParseException e) {
         logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
      } catch (Exception e) {
         logger.log(Level.SEVERE, "Couldn't send echo.", e);
      }
   }
}, new PacketTypeFilter(Message.class));

And handleMessage() looks like this:

private void handleMessage(Map<String, Object> jsonMap) {
   // only present for "ack"/"nack" messages
   Object messageType = jsonMap.get("message_type");
   if (messageType == null) {
      // Normal upstream data message
      CcsMessage msg = getMessage(jsonMap);
      handleIncomingDataMessage(msg);
      // Send ACK to CCS
      String ack = createJsonAck(msg.getFrom(), msg.getMessageId());
      send(ack);
   } else if ("ack".equals(messageType.toString())) {
      // Process Ack
      handleAckReceipt(jsonMap);
   } else if ("nack".equals(messageType.toString())) {
      // Process Nack
      handleNackReceipt(jsonMap);
   } else {
      logger.log(Level.WARNING, "Unrecognized message type (%s)",
      messageType.toString());
   }
}

The PacketListener has just one method: processPackage() which takes a Packet as argument.

A data package – that is an upstream message coming from a device – is then delegated to handleIncomingDataMessage(). For my sample project I have modified Google’s original code quite a bit. For one I use a CcsMessage object here that represents the incoming message.

Next I use PayloadProcessors to deal with the different type of messages. For every possible type of message I have a specific implementation of this interface to actually deal with the incoming message. You can of course replace this logic with whatever suits you.

What you do within those PayloadProcessors is very app-specific. The sample code just provides very basic implementations to give you an understanding of how to deal with messages. Hopefully your app has more to offer than my sample :-)

Send messages to Google’s cloud

To send a message to Google’s Cloud Connection Server, you have to follow these steps:

  1. Create the JSON payload
  2. Create a Smack Packet for the message
  3. Send the XML message to Google’s cloud

Create the JSON payload

With json-simple you can create a JSON object from is a map by calling JSONValue.toJSONString(). Each key of the map corresponds to one JSON attribute. In the section about message types I have listed the possible attributes. With this you can first create the map:

public static Map createAttributeMap(
      String to, 
      String messageId, 
      Map<String, String> payload,
      String collapseKey, 
      Long timeToLive, 
      Boolean delayWhileIdle) {
   Map<String, Object> message =
         new HashMap<String, Object>();
   if (to != null) {
      message.put("to", to);
   }
   if (collapseKey != null) {
      message.put("collapse_key", collapseKey);
   }
   if (timeToLive != null) {
      message.put("time_to_live", timeToLive);
   }
   if (delayWhileIdle != null && delayWhileIdle) {
      message.put("delay_while_idle", true);
   }
   if (messageId != null) {
      message.put("message_id", messageId);
   }
   message.put("data", payload);
   return message;
}

Using this method creating a JSON string for sending a message is simple:

public static String createJsonMessage(
      String to, 
      String messageId, 
      Map<String, String> payload,
      String collapseKey, 
      Long timeToLive, 
      Boolean delayWhileIdle) {
   return createJsonMessage(
         createAttributeMap(
               to, 
               messageId, 
               payload,
               collapseKey, 
               timeToLive, 
               delayWhileIdle));
}

public static String createJsonMessage(Map map) {
   return JSONValue.toJSONString(map);
}

Create a Smack Packet for the message

Creating a Packet object is even simpler. Google’s code makes use of the extension mechanism of Smack. Smack’s extensions are handlers for specific message types. The code uses them for processing incoming as well as outgoing messages.

Google’s inner class GcmPacketExtension is an implementation of Smack’s PacketExtension interface.

It’s method toPacket() creates an XML Packet, in this case it wraps the JSON with appropriate XML as required by XMPP.

Packet request = new GcmPacketExtension(jsonRequest).toPacket();

Send the message to Google’s cloud

If you have a Packet object you simply call send() on your XMPPConnection object that you created connecting to Google’s server in step one.

My demo follows Google’s sample code in combining the last two steps in the method send() of the CcsClient class:

public void send(String jsonRequest) {
   Packet request = new GcmPacketExtension(jsonRequest).toPacket();
   connection.sendPacket(request);
}

Sending to multiple recipients via Google’s Cloud Connection Server

You cannot send a message to multiple recipients when using Google’s Cloud Connection Server. Instead you have to send one message for every registration id you want to send a message to. That’s why I added the message sendBroadcast() which simply iterates over all recipients:

public void sendBroadcast(Map<String, String> payload, String collapseKey,
      long timeToLive, Boolean delayWhileIdle, List<String> recipients) {
   Map map = 
         createAttributeMap(null, null, payload, 
         collapseKey, timeToLive, delayWhileIdle);
   for (String toRegId: recipients) {
      String messageId = getRandomMessageId();
      map.put("message_id", messageId);
      map.put("to", toRegId);
      String jsonRequest = createJsonMessage(map);
      send(jsonRequest);
   }
}

Note: There actually is one option to target multitple registrations ids with just one message. With user specific messages you can target all devices of one user. But you’re still limited to one user only with this option. Since I’m going to cover user specific messages in my next post, I won’t deal with this option here.

You can combine HTTP and XMPP

Google allows you to use HTTP at the same time as XMPP to send messages to devices. It’s up to you if you want to use XMPP just to receive upstream messages of devices and to acknowledge those messages or if you want to use XMPP to talk to Google’s Cloud Connection Server (CCS) for everything.

Actually there is one use case for which you have to use HTTP – at least at the moment. I very much hope that this will change when the final version of those new services is released for everyone. I will cover that specific use case next week.

One final thing

I have written most of the server code in preparation of my talk at the Dutch Android User Group meetup. As I have written in my previous post about Google Cloud Messaging, you have to sign up to use the new features like upstream messaging, XMPP or user notifications. After signing up, Google processes your request and some time later comes back with the approval. In my case the approval took a while and the preparation for the talk was in jeopardy.

Gladly Dennis Geurts offered to use his testing API key and project id for which he had signed up much earlier. A big thanks for that, Dennis!

Lessons learned

With this post I have shown you some aspects of the server side of Google Cloud Messaging using the new upstream messaging model.

You have seen the different message types, have heard of the need to acknowledge messages and how to receive and send messages using Smack’s Java library for XMPP. Since XMPP is text based those code snippets should be easy to transform to any other language.

Together with the source of the demo project this post should get you on the right track to set up your own project.

If you want to start using Google Cloud Messaging, be sure to read the official documentation. I couldn’t cover all in this post. Be sure to not forget the document about advanced topics. There is also a nice blog post by Ryan Oldenburg of Pushbullet about some thinks to keep in mind when using GCM. It might help you to avoid problems right away. For another perspective on the topic you might also want to read Antoine Campbell’s Cloud Connection Server Tutorial.

One final problem: Right now I don’t know any SaaS or BaaS provider to support the XMPP messaging model for Google Cloud Messaging. This is a serious limitation in my opinion – one which I expect to get much better when this model gets adopted more often and is published to all without approval process. Should you know of any provider supporting the new GCM model, please drop me a line.

Upstream Messages With Google Cloud Messaging

Google announced a new messaging model with Google Cloud Messaging on last years Google IO. This model allows for upstream messaging and for user specific notifications. This post is the first in a three-part series in which I am going to look into both these changes and to show you how to use them.

I had never written these posts if it weren’t for the Dutch Android User Group meetup in Utrecht (January 2014), where I had the pleasure to talk about this topic. This event was well-attended and was packed with interesting talks about the changes in Android 4.4 and Google Play Services. If you have ever the chance to attend a meetup of our Dutch colleagues, I strongly suggest to do so. It has been a gorgeous evening and was well worth the two-hour drive. It was not just the talks but also the overall atmosphere as well as the conversations during the breaks and afterwards. A big thanks to the organizers for the awesome evening!

You can find my slides on the speakerdeck site. And a video of the talk should also be available pretty soon.

Sample App

I have published sample apps on github where you can see how to use this in context. For the Android client clone the gcm_sample project. For the server clone the gcm_server project.

What’s new

With Google Play Services 3.1 Google made some changes to Google Cloud Messaging:

  • You can send messages upstream from the user’s device
  • You have to use a permanent connection between your backend and Google’s services
  • You can use user specific notifications

In this post I will only cover upstream messaging. That is the flow of events and what to do on Android’s side. In my next post I’m going to cover the server side – and in the third post I will write about user specific notifications. User notifications allow you to send user specific messages with the possibility to cancel notifications on other devices if they have been consumed already on one device.

Upstream messaging

With the new GCM release Google allows you to send messages directly back to Google’s cloud. That’s what they call upstream messaging. Have a look at the following diagrams. The first one is the traditional model of Google Cloud Messaging while the second one shows the new flow of events.

The classic communication flow with Google Cloud messaging

The classic communication flow with Google Cloud messaging


The communication model of Google Cloud Messaging with the new Cloud Connection Server

The communication model of Google Cloud Messaging with the new Cloud Connection Server

The first two steps in both diagrams are the same: You tell the Google Cloud Messaging API that you want to register a device (step 1). If the registration succeeds Google returns the registration id for this device (step 2).

Traditionally you would then send the registration id back to your server (step 3). The protocol was up to you but very likely HTTP. The server would (hopefully) respond with a success message (step 4).

From then on your server could send messages to Google’s Cloud Messaging service (step 5) and the user’s device would receive it, if it’s registration id was part of the registration_ids parameter of the message (step 6).

With upstream messaging though your app would send the registration id (step 3) not directly to your server, but instead call a method of the Google Play Services API. Google Play Services would then send the message to Google’s servers.

Google then processes the message and sends it to your backend. Obviously for this to work your backend must be connected in some way to Google’s cloud. I will deal with this part in my next post. For now it’s enough to know that there has to be a permanent connection between your backend and Google’s cloud and that Google will deliver messages that way (step 4).

After the registration id has been transmitted successfully you can send messages to the device (step 5). But with the new way to use Google Cloud Messaging you would use the existing connection between your server and Google’s servers and use a different protocol (with slightly different parameters).

Note that Google uses different names for its servers depending on which transmission model you want to use. Google uses the name “GCM HTTP Connection Server” for those servers receiving HTTP messages and it uses “GCM Cloud Connection Server” for those receiving XMPP messages via the permanent connection. The abbreviation CCS is very commonly used within GCM’s documentation.

Create your credentials

If you already use Google Cloud Messaging you can skip this part and proceed to the next section.

If you’re new to Google Cloud Messaging, you have to create an API key in Google’s Cloud Console/Google Developer Console. Do not confuse it with the Google Play Developer Console. Both are unrelated.

After logging in to the Cloud Console you will see a list of projects. Simply create a new one and give it a name and a project id in the next dialog. Now this could be a source of confusion. The project id you use here is not the project id you have to use in your code later on. It’s just a name which nevertheless has to be unique.

Afterwards creating the project the developer console will show you the project’s page. Go to “APIs & Auth” in the menu and turn on “Google Cloud Messaging for Android” in the huge list of Google’s services. Since Google displays all your active services at the top, the entry will move directly to the top after you enable it. Don’t be irritated by that tiny UX glitch. Simply scroll to the top and you will see that it’s status has changed to “On”. That’s great.

Switch to Credentials in the menu on the left. At the top of the new screen you can find a client id. It starts with a number followed by “.apps.googleusercontent.com”. Select the number (only the number), copy it and paste it into your strings.xml – or a special gcm_strings.xml that only contains the project id. Name the string whatever you like – in the sample project I expect a string named gcm_project_id.

That’s all you need for the Android part. But since you’re logged in to the dev console anyway, let me show you how to create the API key for your server right away.

Go back to the dev console. On the Credentials page there are two sections. The OAuth section on the top is where you have found the project id. Below of it is the section called “Public API access”. It’s still empty. Click “Create New Key” and in the next dialog select “Server key”. Afterwards you will see the API key for server applications together with some additional information. You will use the API key when following my post about the server side of GCM.

Sign up for using the new features

To be able to use all the shiny new features of Google Cloud Messaging, you have to sign up first. With the sign up form you “Sign up to be a trial partner”. The new services are not yet finalized. It’s a bit like it has been with Google Cloud to Device Messaging (C2DM) – the predecessor to GCM. You had to sign up as well, and when the service was finally made public, it had evolved to Google Cloud Messaging. So expect the API to change!

Using Google Play Services

You need to use Google Play Services from within your app for registering the device for as well as for sending upstream messages.

Setting up Google Play Services is easy, but requires too many steps to cover them in this post. And those steps also are different depending on whether you use Android Studio, Eclipse or something else. Have a look at the Play services documentation if it’s the first time you use Google Play Services.

The very first step in your code when using Google Play Services is to make sure that Google Play Services are available at all. You can do so with the following snippet:

private boolean checkPlayServices() {
   int resultCode = 
         GooglePlayServicesUtil
            .isGooglePlayServicesAvailable(getActivity());
   if (resultCode != ConnectionResult.SUCCESS) {
      if (GooglePlayServicesUtil.
            isUserRecoverableError(resultCode)) {
         GooglePlayServicesUtil.getErrorDialog(
               resultCode, 
               getActivity(),
               RC_RES_REQUEST).show();
      } else {
         Log.i("grokkingandroid", 
               "This device is not supported.");
      }
      return false;
   }
   return true;
}

What to do when the services are not available, depends on how important they are for your app. If Play Services are not essential, I suggest to let the user know – but in an unobtrusive way. After all the app is usable without it, so do not annoy your users with dialogs or other stuff that keeps them from doing what they actually installed the app for.

Registering the device for Google Cloud Messaging

The next step is to register the device. Google needs to know about your device before your app is allowed to receive or send messages.

In my sample app the user has to explicitly click the button register. Not a typical use case, but for the sample this makes sense. Now when to do this is in a real app is up to you. But when your app benefits from Google Cloud Messaging you usually want to register the device as soon as possible.

I also let the user select a Google account. Your app’s users do not need one for Google Cloud Messaging. I solely request one to use this account for user specific notifications. I will cover those in the third post of this series.

Registering actually is very easy. First get hold of a GoogleCloudMessaging object and then simply call its method register() passing in the project id of the dev console (see “Create your credentials” above):

String projectId = 
      getResources().getString(R.string.gcm_project_id);
GoogleCloudMessaging gcm = 
      GoogleCloudMessaging.getInstance(this);
String regid = gcm.register(projectId);

Be careful though: Asking for the registration id is a blocking request. Hence, you should always use the call in a separate thread off the main thread (UI thread). In the sample project I am using an IntentService to achieve this.

Send messages upstream

As soon as the device is registered, it can send messages upstream – as well as receive messages. Probably the very first message to send upstream is the newly received registration id.

Sending messages is nearly as simple as registering. You create a Bundle with all the payload data you want to transmit and you also have to create a unique message id. In my sample code I simply increase a counter I keep within the SharedPreferences for the message id. Depending on your payload the code might look more or less like this:

try {
   Bundle data = new Bundle();
   // the account is used for keeping 
   // track of user notifications
   data.putString("account", account);
   // the action is used to distinguish 
   // different message types on the server
   data.putString("action", Constants.ACTION_REGISTER);
   String msgId = Integer.toString(getNextMsgId());
   gcm.send(projectId + "@gcm.googleapis.com", msgId,
         Constants.GCM_DEFAULT_TTL, data);
} catch (IOException e) {
   Log.e("grokkingandroid",
         "IOException while sending registration id", e);
}

As you can see you once again need a GoogleClientMessaging object and call its send() message.

This message takes as parameters the project id appended with the fixed string “@gcm.googleapis.com“, a unique message id, a time to live value and the bundle with your payload.

You might notice that I do not include the registration id as part of the payload. That’s because Google Play Services adds the registration id to every message to your backend anyway. You will see in the next post which parameter Google uses for the registration id. For now, just keep in mind that above code is all that is actually needed.

Those strings within the bundle are not even necessary. I use the account because I want to send user specific messages and I use the action to differentiate on my server between different message types.

As you can see there is no special message for sending the registration id back home. It’s just a message like any other upstream message.

Benefits of Upstream messaging

Now that you know how to send upstream messages, you might wonder about why to use upstream messaging in the first place. Why not send your message back to your server as you always did (assuming you did contact your server)?

There are three reasons on the Android side for using the new model:

  • The upstream messaging API is dead simple
  • Upstream messages can reuse connections
  • Upstream messages are needed for notification cancellation

The API is dead simple

You have seen how simple the Android code is. It’s just some message calls to Google Play Services’s GoogleCloudMessaging class. It’s really just this one class, which with only six public methods is not too difficult to grasp :-)

Contrast that with using HTTP instead: When talking back to your own servers directly you have to take care of checking if the network is available, send off the message, check for any error conditions and enqueue the message for later delivery if anything goes awry. All in all you’re better of with upstream messaging – at least for as long as you only care about the Android code.

Upstream messages can reuse connections

Not only is the API easier to use, it can also save resources. The user’s device has a connection to Google anyway so with upstream messaging Google Play Services can reuse this connection. The services take care of using the most power efficient way to send messages so you do not have to deal with that. This helps keeping the battery usage of your app to a minimum.

Of course if your app only sends messages every once in a while, your users won’t notice any change in the battery usage. But if your app has to send many messages to your backend, this might make a difference to your users.

Upstream messages are needed for notification cancellation

The strongest argument for using upstream messaging though is notification cancellation. If you send messages from your server to specific users, you do not want them to see a notification on each and every device – even if it has long been read on another device. I will deal with user specific messages and notification cancellation in my third post about Google Cloud Messaging. So stay tuned :-)

Permissions

To use Google Cloud Messaging you need quite a lot of permissions:

<uses-permission 
   android:name="android.permission.INTERNET" />
<uses-permission 
   android:name="android.permission.GET_ACCOUNTS" />
<uses-permission 
   android:name="android.permission.WAKE_LOCK" />
<uses-permission 
   android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission 
   android:name=
      "com.grokkingandroid.sampleapp.samples.notifications.gcm.permission.C2D_MESSAGE"
   android:protectionLevel="signature" />
<uses-permission 
   android:name=
      "com.grokkingandroid.sampleapp.samples.notifications.gcm.permission.C2D_MESSAGE" />

The first three are predefined permissions. You might notice the account permission. Actually this one is only needed for API levels before Android 4.0.4. I added it for completeness.

The fourth is a bit of an oddity. It’s the old Cloud to Device Messaging (C2DM) permission. For backwards compatibility it makes sense to not change it – otherwise existing apps had to ask for a new permission. But it looks weird about two years after C2DM was deprecated.

You also have to create a new permission of your own. That’s the permission that ensures that no other app can receive messages intended for your app. It has to exactly follow this naming convention: Package name plus “.permission.C2D_MESSAGE“. Otherwise your app won’t receive the messages sent to it. Your app also must use this newly created permission.

Receiving messages

Of course the fun part of Google Cloud Messaging is to actually receive push messages from the cloud. Google transmits the messages to your app to a BroadcastReceiver.

The following code is basically the same as Google’s sample code on their client page:

/**
 * See http://developer.android.com/google/gcm/client.html
 */
public class GcmBroadcastReceiver 
      extends WakefulBroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
      // Explicitly specify that
      // GcmIntentService will handle the intent.
      ComponentName comp = 
            new ComponentName(
               context.getPackageName(),
               GcmIntentService.class.getName());
      // Start the service, keeping the 
      // device awake while it is launching.
      startWakefulService(
            context, 
            (intent.setComponent(comp)));
      setResultCode(Activity.RESULT_OK);
   }
}

The Broadcastreceiver gets the message – but since it runs on the UI thread it should immediately pass the message on to some background thread. I use the same IntentService you have already seen for registering the device.

Actually parsing the message and doing what has to be done is done in the service. Again The code is pretty much the same as on Google’s documentation:

// handling of stuff as described on
// http://developer.android.com/google/gcm/client.html
try {
   Bundle extras = intent.getExtras();
   // The getMessageType() intent parameter
   // must be the intent you
   // received in your BroadcastReceiver.
   String messageType = gcm.getMessageType(intent);
   
   if (extras != null && !extras.isEmpty()) {
      /*
      * Filter messages based on message type. 
      * Since it is likely that GCM will be 
      * extended in the future with new 
      * message types, just ignore any message 
      * types you're not interested in, or that you
      * don't recognize.
      */
      if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
            .equals(messageType)) {
         sendNotification(
            "Send error: " + extras.toString());
      } 
      else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
            .equals(messageType)) {
         sendNotification("Deleted messages on server: "
            + extras.toString());
      } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
            .equals(messageType)) {
         // Post notification of received message.
         String msg = extras.getString("message");
         if (TextUtils.isEmpty(msg)) {
            msg = "empty message";
         }
         sendNotification(msg);
      }
   }
} finally {
   // Release the wake lock provided by the WakefulBroadcastReceiver.
   GcmBroadcastReceiver.completeWakefulIntent(intent);
}

As you can see GCM uses different message types. the last one is the one actually containing a new messages. The first one informs you about errors when sending messages and the second tells you that messages have been deleted. If for example you display incoming messages with a notification you would have to cancel the notification in this case.

What to do when receiving an actual message is very specific to your app. The sample app simply displays a notification.

Do not forget to release the wake lock. That’s the line within the finally block. The finally block ensure that this call will always be done – even if any exception has been thrown in the code within the try block. Be sure to do it that way!

Lessons learned

In this post you have seen how the message flow has changed when using Google Cloud Messaging. With the previous model you had to contact your server directly from the device, now you only tell Google Play Services what to do with the new upstream messaging model. Google’s services take care of actually delivering the message to your server.

You also have learned about how to set up the project in Google’s developer console and that you have to sign in to use the new features.

Finally you have seen how easy the Android code actually is and what the benefits of upstream messages are.

In the next post you will learn more about the server side of upstream messaging – which is a tad more complex. And after that I’m going to show you how to use user notifications in the final post of this series.

Chrome-Apps on mobile devices – a good idea?

Google announced a new set of tools this week to help developers publish their Chrome apps on iOS and Android. That’s the next logical step by Google to win over more developers for Chrome apps. In September Google already announced that from then on developers could publish their Chrome apps as offline apps, allowing users to use them like any other desktop application. Those offline apps from now on can also be published on iOS and Android. BTW: It’s interesting that Windows Phone is no target platform for Chrome apps and hasn’t even been mentioned on the blog post.

To make this work, Chrome apps have to use a thin wrapper to be considered a “native” app and to access phone functions not available via HTML 5 as of yet. For this Google uses Apache Cordova, better known as Phonegap. With the help of this project and further additions made by Google, Chrome apps can be published on Google Play and Apple’s App Store. You can read more about it on Google’s blog post.

Users cannot recognize those apps as Chrome apps in the respective app stores. They just show up as any other app. And that’s where the problem starts.

Taking a web app, which works fine on a desktop, wrapping it with some tools and publishing it, that’s just not enough. Those apps would fall short of users’ expectations.

First of all those apps would look totally out of place. Just have a look at this screenshot of Google’s blog post:

Screenshot of one of Google's sample apps

Screenshot of one of Google’s sample apps

There’s no action bar, those buttons look weird, the header is very unusual – it just doesn’t fit. Of course you could get around most problems and make it look properly – but that would require some additional work. You would no longer just wrap an existing app, but start to provide platform specific deviations to achieve proper designs.

Secondly interaction patterns on the web, on desktop apps and on mobile apps are totally different. Consider the differences between iOS and Android alone. Tons of difference like navigation patterns, action placements, list treatment and so on. This problem is much worse and has much more influence on whether an app feels like a properly done app or not. And no cross-platform tool can help you with that. You will end up with multiple versions for all supported platforms anyway. Just consider the code. You probably can structure this in a way that is maintainable – but not if the main reason for taking this route was saving costs in the first place.

Third I wonder about the quality of the apps. This is a very personal fear based on my experience with Firefox OS apps. Those are very often normal desktop apps as well – which too often do not work on a mobile device. It might happen, that desktop app developers simply wrap up their app and do neither test properly nor know about those limitations. Of course those apps would get ratings that bad, that they wouldn’t show up for most searches anyway. But Google is setting expectations for devs here – and those devs might be very disappointed down the road.

As you’ve seen there are plenty of issues with the user experience. But obviously technical issues exist as well.

It seems that it’s not that easy from a technical point of view as Google makes us believe it is. Just have a look at the sample apps. Five (!) of those 17 apps do not run on Android at all. Another six only with limitations. Or put it another way: Only one third of those apps works properly on Android. For iOS it’s about the same (though with different apps): Six apps don’t work at all, another five only with limitations. Only two out of 17 apps work properly on both supported platforms! And this is about to help devs? This should be a proper way to develop cross-platform apps? Not at all!

The only thing that I am confident to work properly is the responsiveness of those apps. Web developers do that for years. They understand and grok responsiveness.

If you want to publish apps and want your users to like your apps, you have to take the patterns and specifics of each platform into consideration. That means work. No matter which approach you choose. I guess that the total amount of work is even less if you design and develop different apps for Android, iOS, Windows Phone and (hopefully) Firefox OS than when you try to use a cross-platform tool. And I have yet to see a cross-platform app that actually does work properly on different platforms.

Google has done so much in recent years to consolidate the design, interaction patterns and overall usability of Android. Which makes the recent announcement all the more disappointing. It’s a step backwards. It’s going back to where we were some years ago: A world without a unified design language without common interaction patterns. I do not want this. And I strongly believe, users do not want this as well.

As a developer you have to keep an eye on this project. At least because your clients might mention it. But it’s not working. At least not yet. If it ever will – I do not know.

Project managers and product managers should also carefully consider the limitations of this approach. Don’t think it will save you money! Don’t think it will save you time! If you’re not careful and use it without proper analysis, you’re bound to see costs rising unexpectantly (well, actually that’s to be expected) and your users will still rate your app poorly.

Note: This post has initially been written for the German publication computerwoche.de.

FirefoxOS – my Initial Impression

Quite a while ago I ordered a Peak+ FirefoxOS phone at geeksphone.com. Alas after some delay it finally was cancelled – so I settled for the smaller version, the normal Peak. About a week or two ago it finally was delivered. After some very short initial testing I had more pressing things to do. But this week I gave it another look. Here are my initial impressions – mostly of FirefoxOS and less of the Peak itself.

The phone itself

I was quite suprised by the size of the device. It’s roughly the same as the N5 – though the screen is much smaller and the screen resolution even more so. That’s not so good – but it’s a dev phone, so it’s not really that important. But for any handset maker out there: If your screen doesn’t provide the resolutions current top devices spout, please make your device smaller.

Of course the phone is plastic all around – it’s after all a cheap phone. I do not mind. I never thought, that plastic feels cheap. Actually I prefer plastic over metal or – even worse – glass. So it feels quite good – albeit a tiny bit too large. Some rubberized finish would be a nice addition, though.

The screen is surprisingly good. Of course the resolution is far away from those of top device, but mostly good enough. Only for screens with much text, the resolution is an issue.

The camera of course isn’t great – but for simple snapshots it should be sufficient. You won’t ever win a price with those pictures though.

Battery life: Seems to be good, very good indeed. But that’s just an initial impression. I have yet to make the phone my primary device for a few days. Something I am not quite ready to do so, yet. You will see in the next section, why not.

UX issues

FirefoxOS is full of UX issues. I’m a developer and definitely no UX expert. But even I can spot many problems. Users will notice, will stumble upon those issues and think that something’s not right. So in my opinion, Mozilla should concentrate on those issues – especially some stuff that from an outside perspective looks like something that should be easy to fix. Of course I know that this outside perspective is often misleading, but hopefully some issues are easy to fix.

Touch feedback is rare. Which is a deadly sin for a touch based interface. Take the Action Bar (in FirefoxOS slang it’s the Header). When I hit back in the top left corner, I want to see the back indicator highlighted. But that’s not happening. So did I touch it? Should I touch again? And it’s not just in the FirefoxOS Header.

Missing touch feedback is sometimes made worse by a lacking loading indicator. I want to see a spinning wheel or some other indicator that content is loading – let me know that you do something. I hit back twice over and over because I had no feedback whatsoever.

Firefox Marketplace app lacks touch feedback as well as loading indicators all over the place. And the app doesn’t seem to cache anything. It feels like the app reloads all lists whenever I go back to them. That slows things down considerably and make missing feedback even worse.

The next issue might partially be based on my Android experience. But whatever the reason: I miss the back button dearly. I’m not using “up” often on android and having to go up to the Header/Action Bar feels very weird. But it’s not only uncomfortable, it’s sometimes even problematic. What to do on with an information dialog? I happened to stumble upon that at least once. Granted, it’s the fault of the app, but nevertheless a problem that could be hurting the OS adption.

The lock screen is also a UX fail. You first have to pull up a bar from the bottom – which is nicely indicated by an appropriate animation. But afterwards you have to do another step: You have to click on the unlock icon. Two steps to unlock the phone? That’s one step too much. As simple as that!

The list of opened apps also has a problem. There’s a button to close this app – which works more or less randomly. Swiping the app away, though, works fine all the time.

I had some trouble with flinging through lists. One problem: When flinging repeatedly in long lists, the flow stops. Don’t know how to describe this correctly. But the new movement of my finger stops the last one and starts a new fling. That feels very unnatural. It doesn’t feel like a continuing movement.

Another one is the notifications drawer. You have to drag it all the way down to see the top most notification. Which is bad if you just want to peek at the notification. It feels totally strange to have to scroll that far to finally see the one notification that caused you to use the notification drawer in the first place.

The on screen keyboard also feels kind of weird to me. Cannot exactly nail it, but it just doesn’t feel right. Of course on Android I swipe most of the time, but it’s not just that. The spacing between keys is very narrow, but I guess that isn’t it either. Hopefully I can tell you in a follow-up post, what it is that actually bothers me. Right now it’s just the feeling: This is not right. The only thinkg, I can tell you for sure, is the surprising location of the “‘”. It’s right next to the letter “l” and directly above the return key. I accidentally hit it way too often.

Apps

The general quality of the app is not great – to say the least.

One example: Pulse as one of the top apps promoted in the news category. When starting Pulse for the first time, the first thing you see, is the suggestion to get the app! WTF! I do not know about the reason, but my guess is, that this Pulse “app” is simply the mobile website. Don’t know if this is Pulse’s fault or Mozilla’s fault, but it sheds a bad light on the platform. This shouldn’t happen. This mustn’t happen!

Next I downloaded a Pomodoro timer and a kitchen timer. Neither of these works when the OS goes into sleep mode. What? A timer not ringing, when the screen turns off? These seem to be apps for a desktop firefox. If they do not work properly on FirefoxOS, those apps shouldn’t be available in the marketplace on these devices. Some quality assurance must take care of that. I actually found not one timer app that deals with this correctly.

Another example is the stock Camera app. When taking a photo and viewing it from within the Camera app, I sometimes got a black screen when enlarging the picture. Initially I thought the app just crashed (or run into some endless loop), but all buttons were still visible and reacted properly. Actuall it’s just that the screen remains black until the enlarged picture is ready to be displayed. Which can last an astonishingly long time. This is a horrible user experience – just show me some blown up but undetailed preview of the area and display more details progressively.

The Marketplace app itself has problems. I do not want to see many apps, I want to see quality apps. One timer would be enough if it works properly and has at least a decent usability. But about ten timers and none working as expected, that’s about as useful as no timer at all. I also do not need all soccer leagues of the world. I want to find the one local to me (granted, some leagues might be more interesting to others worldwide than others, but I gues most people want to see the league of their home country). Same goes for news and anything else. I am still asztonished that Google doesn’t provie a better search experience on Google Play, but now I can appreciate what they have been doing. Definitely the results are more relevant than thos in Firefox market place.

Importing stuff

As an Android user I obviously have stuff on Google’s server. My contacts, my calendar, mail, what not. I was able to import contacts flawlessly, but strangely enough I couldn’t import any calendar information. No error dialog, it simply stopped after I entered all credentials. This is crucial and could be a big issue for FirefoxOS.

And since we’re at it: A central account setting makes life so much easier. That’s something Android does very well. Not just for Google accounts, mind you. But for any apps that make use of sync adapters and authenticators. It’s cumbersome to have to enter the credentials over and over again because there isn’t such a central place in FirefoxOS.

Initial verdict

Boy, Mozilla has still a lot to do. I still very much hope for FirefoxOS to succeed. That’s why I ordered the phone in the first place. I love Android but Android needs another viable open competitor. Microsoft and Apple obviously do not fit that description.

But to be competitive in the market place, there is still much to do for Mozilla and app devs developing for FirefoxOS.

Then Mozilla needs to adress the usability issues. There are probably many more I didn’t even notice. But that’s what makes users recommend a system if done right. If done wrong, though, users most probably will advise against buying it. Shouldn’t happen.

And of course we do need more apps. For this FirefoxOS has to gain more traction. The usual catch-22 situation of all the follow-up systems in the mobile space. That’s something we all can contribute to. If you want FirefoxOS to succeeed, help Mozilla out wth an app or two :-)

Of course all is open source, so if you want to do so you can also help with all the other issues, I mentioned. Mozilla probably would be very happy about any new contributors to the platform.

This all sounds pretty dim. But you have to consider that it’s only an initial impression. Then version 1.2 is in the making and might (hopefully) correct many of the issues. I personally still have hope for the platform. So much actually that I’m giving development for it a try and to publish an app myself. I will let you know about this in a future post. But: This is still an Android centric blog. FirefoxOS related posts will only be sparse in between.

Let me know what you think and what your experience with FirefoxOS has been.

Migrating from ActionBarSherlock to ActionBarCompat

In July 2013 Google announced ActionBarCompat as part of its support library package. This library makes it easy to use the Action Bar that have to support older devices. Many have waited for this to happen ever since the Action Bar was introduced with Honeycomb.

I, though, didn’t expect that to happen. After all the Action Bar was announced long ago and we had ActionBarSherlock. So why all off a sudden?

I have written multiple posts about ActionBarSherlock on this blog prior to this announcement. Those posts still get a lot of attention and search hits. But while the basic concepts still apply, any ActionBarSherloc specific parts are kind of deprecated :-)

I strongly believe that you should use ActionBarCompat for all new projects that want to support older devices. It also might make sense to migrate existing projects. So read on to learn why you should migrate or use ActionBarCompat right away and how to migrate existing projects.

Why you should prefer ActionBarCompat over ActionBarSherlock

There are many reasons why you should prefer ActionbarCompat over ActionbarSherlock.

First of all this project is by Google, is part of the Support Library and thus likely will support new Action Bar related stuff at the same time Google releases them with stock Android.

Another good reason and a proof for the previous point is that ActionBarCompat supports the Navigation Drawer pattern right out of the box, while ActionBarSherlock does not. Thus if you want to add this drawer to an existing project/app you should migrate.

The last and not least reason is, that the creator of ActionBarSherlock, Jake Wharton, announced on Google+ that further development of ActionBarSherlock has been stopped. ActionBarSherlock 4.4 is the last release and might get bug fixes – but there won’t be any new features:

While there may be a dot release or two in the coming weeks, version 4.4 is shaping up to be The Last Releaseā„¢.

He’s not too sad either :-)  See this quote, Jake Wharton made on his blog about ActionBarSherlock being intended to be thrown away eventually:

This is the entire purpose of the library. It has been designed for this use case specifically. It has been deprecated from inception with the intention that you could some day throw it away.

Sample project

To showcase how the migration works, I have migrated the sample project ActionViews to ActionBarCompat. This sample project shows how to use the Action Bar with older devices and as a special case how to use ActionViews within your Action Bar. You can find more information about ActionViews on my older post. While originally written with ActionBarSherlock in mind, you can easily transfer those code samples to ActionBarSherlock. The next sections show you how to adapt the code snippets to move from ActionBarSherlock to ActionBarCompat.

You can find the ActionViews sample project on bitbucket. If you like you can see all changes necessary for the ActionBarCompat migration by viewing the commit.

Of course you have to integrate ActionBarCompat in the IDE of your choice. I do not cover this here. Gabriele Mariotti has written an excellent post covering the IDE integration of ActionBarCompat. I originally developed this project using Eclipse – which is why I occasionally refer to Eclipse specific shortcuts or why I include an Eclipse dialog later on. But the core of this post is independent of the IDE you want to use.

How to proceed

So I assume that you have removed ActionBarSherlock from the ActionViews project and added ActionBarCompat instead. After that your project should be plagued with errors. Which is not too surpising. In the next sections I will take you through all the steps needed to get the project deployable again.

I start with the resources and deal with code changes later on. Android’s Development Tools only generate a new R.java file when the resources are error-free. And without a correct R file your Java sources won’t compile properly. Thus I prefer to fix resources first.

Changing the style

The first thing to do, is to correct the style. I have used an ActionBarSherlock style previously. This style has to change to the proper ActionBarCompat style. And as with ActionBarSherlock you have to use an ActionBarCompat style, otherwise you’ll get a RuntimeException at app start.

Change the style with the name AppBaseTheme to use Theme.AppCompat.Light.DarkActionBar as its parent:

<style name="AppBaseTheme" 
      parent="@style/Theme.AppCompat.Light.DarkActionBar">
   <!-- nothing API level dependent yet -->
</style>

Since you might forget this step in future projects – at least I’m prone to initially forget this step – here’s the Exception that you will see in logcat in that case. Having seen it here might help you to remember what to do about it.

E/AndroidRuntime( 1413): Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
E/AndroidRuntime( 1413): 	at android.support.v7.app.ActionBarActivityDelegate.onCreate(ActionBarActivityDelegate.java:111)
E/AndroidRuntime( 1413): 	at android.support.v7.app.ActionBarActivityDelegateICS.onCreate(ActionBarActivityDelegateICS.java:58)
E/AndroidRuntime( 1413): 	at android.support.v7.app.ActionBarActivity.onCreate(ActionBarActivity.java:98)
E/AndroidRuntime( 1413): 	at com.grokkingandroid.sampleapp.samples.actionbar.actionviews.BaseActivity.onCreate(BaseActivity.java:30)

The dev tools will highlight the attribute android:textIsSelectable somewhere up in the file after you save it. That’s because the minimum API level of the project is SDK 7 and the attribute has only been introduced with SDK 11. You can safely ignore this. If you clean your project after some more fixes, this marker will disappear. You won’t get any problems with lower versions despite this.

Fixing the menu definitions

The next step is to correct the menu definition files. Older Android versions don’t know about the Action Bar and thus do not support those new xml attributes for the Action Bar. So you have to change all attributes with the name android:showAsAction, android:actionViewClass, android:actionProviderClass, or android:actionLayout. The fix is easy. Simply change the namespace from android to app and add this namespace.

For example for the file menu_fragment_expandable.xml the new xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id=
           "@+id/actionViewLayout"
        app:actionLayout=
           "@layout/expandable_actionview_edittext"
        android:icon=
           "@drawable/ic_action_add_inverse"
        app:showAsAction=
           "ifRoom|collapseActionView"
        android:title=
           "@string/add_item"/>
</menu>

I make the namespace known to the parser in line 3. I use this namespace for the Action Bar specific attributes in lines 6 and 8. This way ActionBarCompat can read those attributes and provide the correct appearance of the menu items.

Fixing the Searchview to use

Have a look at the menu_fragment_search.xml file. Neither your IDE nor Android’s Lint checker will flag this file as incorrect. Yet it is.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
      android:id=
         "@+id/searchView"
      app:actionViewClass=
         "com.actionbarsherlock.widget.SearchView"
      android:icon=
         "@drawable/ic_action_search_inverse"
      app:showAsAction=
         "ifRoom|collapseActionView"
      android:title=
         "@string/search"/>
</menu>

Obviously line 7 won’t work any longer. Instead of Sherlock’s SearchView you have to use the SearchView of the ActionBarCompat library. You now have to use the class android.support.v7.widget.SearchView. The updated file should look like this:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
      android:id=
         "@+id/searchView"
      app:actionViewClass=
         "android.support.v7.widget.SearchView"
      android:icon=
         "@drawable/ic_action_search_inverse"
      app:showAsAction=
         "ifRoom|collapseActionView"
      android:title=
         "@string/search"/>
</menu>

Should you forget this step in a project of yours, you are going to see an exception in logcat:

W/SupportMenuInflater( 1308): Cannot instantiate class: com.actionbarsherlock.widget.SearchView
W/SupportMenuInflater( 1308): java.lang.ClassNotFoundException: Didn't find class "com.actionbarsherlock.widget.SearchView" on path: DexPathList[[zip file "/data/app/com.grokkingandroid.sampleapp.samples.actionbar.actionviews-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.grokkingandroid.sampleapp.samples.actionbar.actionviews-2, /system/lib]]
W/SupportMenuInflater( 1308): 	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
W/SupportMenuInflater( 1308): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
W/SupportMenuInflater( 1308): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater$MenuState.newInstance(SupportMenuInflater.java:480)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater$MenuState.setItem(SupportMenuInflater.java:441)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater$MenuState.addItem(SupportMenuInflater.java:462)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater.parseMenu(SupportMenuInflater.java:196)
W/SupportMenuInflater( 1308): 	at android.support.v7.internal.view.SupportMenuInflater.inflate(SupportMenuInflater.java:118)
W/SupportMenuInflater( 1308): 	at com.grokkingandroid.sampleapp.samples.actionbar.actionviews.SearchViewFragment.onCreateOptionsMenu(SearchViewFragment.java:40)

Whenever you migrate an existing project, I suggest you run a search over all sources – especially the resources. Search for “sherlock” to find out, if you’ve missed any references. Another good candidate for problems is be the manifest file if you previously used ActionBarSherlock styles directly within it.

If you have corrected all menu files, you are done with the resources. Select Project -> Clean to clean the actionviews project and get rid of the android:textIsSelectable error marker. The Android Dev Tools generate a new R.java file and it’s time to have a look at the Java sources.

Fixing fragments

I’m going to show you first how to fix fragments and later on how to fix activities.

Substituting SherlockDialogFragment with DialogFragment

The first and most simple one to fix is the AboutFragment. You have to fix the inheritance since this class inherits from an ActionBarSherlock class which you want to migrate away from. Simply substitute SherlockDialogFragment with DialogFragment and the AboutFragment is fine. Of course you have to correct the imports by hitting Ctrl-O.

Note: Eclipse asks you whether to use an import from stock Android or from the support library. Whenever eclipse offers you this alternative, you always have to use the imports of the support library:

Select the support library versions whenever this choice is presented to you

Select the support library versions whenever this choice is presented to you

Substitute SherlockListFragment with ListFragment

Next up is the SearchFragment. It inherits from SherlockListFragment. Replace this with the stock ListFragment and hit Ctrl-O.

Replace getSherlockActivity() with getActivity()

Two red markers remain – both for the method call to get an activity object. Simply replace getSherlockActivity() with getActivity() and the code is fine again.

Substitute SherlockFragment with Fragment

Now to those other fragments that make up the beef of the sample. Those fragments all inherit from the base class DemoBaseFragment. Again you have to change the type of the super class. Replace SherlockFragment with the stock Fragment class of the support library. Afterwards hit Ctrl-O and change the getSherlockActivity() calls to getActivity() calls as mentioned above.

For the four remaining fragments change the imports first. ActionBarCompat needs no special Menu or MenuItem objects like ActionBarSherlock did. Thus two of the four fragments are immediately correct after fixing the imports. Those other two are a tiny bit more involved.

Use MenuItemCompat for ActionViews and ActionProviders

The problem is with ActionViews – the core content of the sample app. ActionBarCompat uses plain Menu objects. But those do not know of ActionViews prior to API level 11. So ActionBarCompat uses a helper class named MenuItemCompat to deal with ActionViews and ActionProviders.

Instead of calling getActionView() on a MenuItem object you have to use MenuItemCompat.getActionView(). For example the new way to get hold of the ActionView in the SearchViewFragment looks like this:

SearchView searchView = 
      (SearchView)MenuItemCompat.getActionView(item);

The same applies to setting an ActionView. The PlaceholderActionViewFragment for example uses the following lines:

MenuItemCompat.setActionView(
      PlaceholderActionViewFragment.this.mProgress, 
      R.layout.actionview_progress);

For ActionProviders you would have to do the same – just with different method names of course.

Fixing activities

As with fragments you have to change the super classes for the activities as well. The actionviews project uses one base activity for all activities within the project. This class obviously is the starting point for changes to activities.

Replace SherlockFragmentActivity with ActionBarActivity

Changing the super class for activities is slightly different to the changes you applied to fragments in the previous steps. With fragments you simply change them to stock fragments of the support library. With activities on the other hand you have to use a super class of the ActionBarCompat library.

Open BaseActivity and change the super class from SherlockFragmentActivity to ActionBarActivity.

Replace getSupportMenuInflater() with getMenuInflater()

One problem remains after fixing the imports. The first problem is the call to getSupportMenuInflater(). Simply replace it with getMenuInflater() instead.

Replace Sherlock layout IDs

The next activity you are going to fix is the ActionViewActivity. After fixing all imports there are still two red markers left. Those are for sherlock specific layout resources.

First replace R.layout.sherlock_spinner_item with android.R.layout.simple_spinner_item. Next replace sherlock_spinnner_dropdown_item with android.R.layout.simple_spinner_dropdown_item.

The respective lines should look like this after you applied those changes:

ArrayAdapter<CharSequence> spinnerAdapter = 
      ArrayAdapter.createFromResource(
            getSupportActionBar().getThemedContext(), 
            resId, 
            android.R.layout.simple_spinner_item);
spinnerAdapter.setDropDownViewResource(
      android.R.layout.simple_spinner_dropdown_item);

For the two remaining activities, which I didn’t cover yet, you simply have to fix the imports to make them compile again. After that your project should contain no more errrors and should build fine.

Lessons learned

After reading this post you should be able to migrate an existing project which is based on ActionBarSherlock to ActionBarCompat. You have seen good reasons of why to do this and the steps to follow to get your project running again.

There are other great posts about ActionBarCompat out there. Mark Allison wrote a series about ActionBarCompat and Antonio Leiva also has a three part series on ActionBarCompat. The last post also covers migrating from ActionBarSherlock. And Gabriele Mariotti also has multiple posts about ActionBarCompat. We all use different approaches – so look for the post style you like the most. If you feel important parts are missing here, have a look at these other posts.

Till next time. Happy Coding – and Happy Migrating!

ActionViews Sample App is on Bitbucket

The sample app for my post about ActionViews is on Bitbucket. Besides Actionviews it serves also as the sample app for how to add ActionBarSherlock to projects, and for adding action items from within fragments.

Here’s a screenshot of the demo:

The demo app showing the SearchView in its collpased mode

The demo app showing the SearchView in its collpased mode

I plan on generating the scaffold for my demo apps so that I only have to add specific stuff and keep my work for the demos to a minimum. That on the other hand makes some parts of the code look a bit weird, others look pretty generic. You wouldn’t do it that way for a single purpose project.

Since I like to blog about what is happening to me while developing apps, I use this post to tell you about three useful Android tools that I used while developing and preparing this app for release.

The first two can be used to analyze the UI, the third is useful for spotting problems with stuff you might miss because you are too knowledgable of the way your app works.

HierarchyViewer vs. UI Automator Viewer

UI Automator Viewer is a tool that was released with Android pretty recently (sometime last year). According to the Android site it can be used to Analyze your Application’s UI. In fact it is a very nice tool to quickly get an overview of how the UI of an app is structured. UI Automator simply grabs the screen and shows you all views present. Here’s a screen of the Play Music app:

UI Automator Viewer displaying the hierarchy of the Play Music app

UI Automator Viewer displaying the hierarchy of the Play Music app

On the left is the UI, on the right the hierarchy at the top and some properties of the currently selected element at the bottom. As you can see I have selected a tiny image at the bottom right corner of the album shot (whatever it is for).

But the big downside of this tool is that it only shows what you can see. And if you wonder, why something is not visible, it can’t help you. Which I learned the hard way some days ago :-)

I extracted parts of the container’s attributes to a common style. Then I applied this style to the other containers and deleted unnecessary attributes. And by doing so I deleted one attribute too many of a LinearLayout – the android:orientation attribute. A LinearLayout is horizontal by default and since I already had a TextView inside the container (the box header) any additional view wouldn’t be visible.

Lint normally warns about that, but in my case I add the views in the code – and thus Lint couldn’t catch the problem. This silly mistake caused me to look in all directions, but not the right one. For way too long!

Here’s what it looked like:

The demo showing the container without the links

The demo showing the container without the links

In retrospect it’s obvious what went wrong and I wonder why I thought of other reasons at all, but well, one is always wiser in hindsight :-) I finally found the missing attribute using a plain old diff and having a closer look at what I actually had removed. But I could have spotted it earlier, had I known about UI Automator’s restriction to visible UI elements. There is a button “Toggle NAF Nodes” but that doesn’t help here either. This button is only useful to see elements which are visible but not reachable via navigational controls like a D-pad.

Another Android tool, HierarchyViewer, could have saved me. This tool is so darn slow that I never really liked it. Which is why I had hoped (thought, actually) UI Automator Viewer would be enough.

HierarchyViewer can be extremely useful, though. It really shows any view that is part of the hierarchy. Visible or not! So let me show you the hierarchy of my demo app, before I corrected my LinearLayout's orientation in both tools.

In HierarchyViewer I immediately see that all my links had been added. But they were outside of the right edge of the screen. The bold red line is where my view is :-)

Hierarchy Viewer showing my missing view

Hierarchy Viewer showing my missing view

Now the same view in the UI Automator Viewer (with the NAF toggle on):

UI Automator viewer isn't showing all the views present in the LinearLayout

UI Automator viewer isn’t showing all the views present in the LinearLayout

So, don’t get me wrong: I know that UI Automator Viewer’s main task is to analyze your UI before writing uiautomator tests, but it would have been nice nonetheless if it could have been used for this as well. It’s a much nicer tool than Hierarchy Viewer.

Monkey

As a last step before releasing, I did a Monkey run. Monkey is a tool that simulates random clicks and interactions with the devices. No user would do it that way, obviously, but by doing so monkey uses combinations and clicks on places you never would do.

By executing it’s random actions, Monkey helps you to find weak spots like Application Not Responding problems or unexpected crashes at odd places. Monkey uses the app in unexpected ways. Ways, of which we think, that no user in his right mind would choose them. But users do! Not because of their state of mind, but because the UI is not as intuitive as we thought. Or because they try to achieve goals that we didn’t think of.

While Monkey runs, the screens of your app flash in quick succession and you see all kind of button presses and so on.

As soon as a problem appears, Monkey stops and shows a modal dialog. One of the very rare cases where a modal dialog is okay. While monkey is running the devices isn’t usable anyway – and you want to see when something goes wrong.

A warning though: Do not use Monkey for arbitrary apps on your device. As I’ve said, it does all kind of things – which means that your data is probably in a bad shape afterwards :-)

With that said, it’s finally time for you to go over to the Bitbucket project page and grab the sources. Let me know any suggestions you have. Thanks!

SQLite in Android

SQLite is at the heart of Android’s database support. This database was developed with embedded environments in mind – and is used not only by Android but also by Apple’s iOS and Blackberry’s system as well as lots of other systems with low memory footprint and comparatively little CPU horsepower.

Why SQLite in the first place?

Of course there is a reason why SQLite is so dominant in the embedded and also the mobile world. The main reasons are

  • Low memory consumption
  • Ease of use
  • Free availability

SQLite in Android consumes very little memory

While SQLite’s memory footprint starts at about 50 kilobyte it’s remains low even for bigger projects with more complex data structures (at about a few hundred kilobytes). Keep in mind: In the mobile world the memory per process as well as total usage of memory is limited compared to desktop systems. Gladly SQLite should not add too much burden to the memory consumption of your app.

SQLite is easy to use

SQLite is a serverless system. I will detail what this means in the next section, but it makes handling of the database that much easier. No need for configuration files or complicated commands. You definitely do do not want these on mobile systems. Those systems must run out of the box without forcing the user to manually configure anything or forcing the developers to consider additional constraints.

SQLite’s source code is released under the public domain

SQLite has a huge commercial backing by the likes of Google, Adobe, Mozilla or Bloomberg. And it is used in many, many products and open source projects. The project is maintained actively so one can expect further imrpovements as well as optimizations in the future. Android for example uses ever newer versions in its SDKs to make use of these improvements.

SQLite is not like any other database

Though SQLite offers quite an impressive feature set given its size, it differs in many aspects from a conventional database system:

  • SQLite is serverless
  • SQLite stores data in one database file
  • SQLite offers only a few data types
  • SQLite uses manifest typing instead of static types
  • SQLite has no fixed column length
  • SQLite uses cross-platform database files

I will delve into each of these points a bit deeper – and add another one that’s only relevant if you want to support older Adroid versions.

SQLite is serverless

There is no SQLite process running at all. You use SQLite more like a library which helps you to access the database files. You do not need to configure the database in any way. No port configuration, no adding of users, no managing of access levels, no tablespace setup and what not. You simply create the database files when you need it. I will cover how to create a database in the next part of this tutorial series.

All data is stored in one single database file

SQLite uses one file to store all the contents of your database. This file contains the main data, as well as indices, triggers and any meta data needed by SQLite itself. Newer versions add a journal file which is used during transactions.

SQLite offers fewer datatypes

The following table shows all types supported by SQLite. If you use other types (like varchar) in your CREATE TABLE statement SQLite maps them as closely as possible to any of these types.

SQLite datatypes

Type Meaning
NULL The null value
INTEGER Any number which is no floating point number
REAL Floating-point numbers (8-Byte IEEE 754 – i.e. double precision)
TEXT Any String and also single characters (UTF-8, UTF-16BE or UTF-16LE)
BLOB A binary blob of data

The biggest problem here is the missing datetime type. The best thing to do is to store dates as Strings in the ISO 8601 format. The string to represent the 28th of March 2013 (the day of publishing this post) would be “2013-03-28“. Together with the publishing time it would look like this: “2013-03-27T07:58“. Stored this way SQLite offers some date/time functions to add days, change to the start of the month and things like that. Note: In contrast to ISO 8601 SQLite doesn’t offer any timezone support.

Also missing is a boolean type. Booleans have to be represented as numbers (with 0 being false and 1 being true).

Although a blob type is listed in the table above, you shouldn’t use it on Android. If you need to store binary data (e.g. media-files) store them on the file system and simply put the filename in the database. More on SQLite types can be found on the SQLite project page.

SQLite doesn’t use static typing

Any type information in SQLite is dependent on the value inserted, not on the data definition of the CREATE TABLE statement. Let’s say you create a column as an INTEGER column. Then you might still end up with TEXT entries in this column. That’s perfectly legal in SQLite – but to my knowledge in no other relational database management system.

This reliance on the value is called manifest typing – something in between static and dynamic typing. In Mike Owens’ book on SQLite you can find a very good and much more detailed explanation of SQLite’s typing.

SQLite has no fixed column length

If you look at the table above you see that there is only a definition for text, but not for varchar(xyz), where you can limit the column to an arbitrary length. In SQLite any TEXT value is simply as long as it is. SQLite adds no restrictions. Which might be pretty bad. To enforce a restriction, you have to do this in your code. SQLite won’t help you. On the other hand you will not get into any trouble if Strings get too long or numbers too large. Well, you will not get any SQLExceptions – though it might break your code in other ways or destroy your UI!

SQLite’s database files are cross-platform

You can take a file from a device put it on your laptop and start using it as if you created it on your laptop from the outset.

It might come handy to pull the database file from the device (or your emulator) and run queries from within your development machine. Especially if you want to use tools with a graphical user interface. One of the best know is the SQLite Manager extension for Firefox which you might prefer to sqlite3 in some cases (see screenshot).

SQLite Manager showing the results of an SELECT statetment

SQLite Manager showing the results of an SELECT statetment

Also you sometimes might want to prepare the database on your development machine and put a database onto your device which contains the needed set of data like a very large dataset to test for performance or a defined database for starting automated tests.

Thanks to SQLite’s cross platform file format it is also possible to deliver a prefilled database with your app to your users. Jeff Gilfelt has written a library to help you with it. You can find his Android SQLite Asset hHelper library on github.

SQLite offers a special kind of table for fast text searches

To help developers create fast text searches SQLite offers also a special kind of database table. The so called FTS3/FTS4 tables. FTS stands for “full text search”. You have to create special tables for it to work and use slightly different SELECT statements (and rarely special INSERT statements) to use them efficiently. But if you do so, you gain tremendous performance improvements for text only search. I will cover FTS in an extra blog post.

Older versions of SQLite do not support referential integrity

The version of SQLite integrated into older versions of Android (3.4 in the early days, later on 3.5.9) doesn’t support referential integrity. This changed with Android 2.2. Thus this problem should fade away pretty soon and is only relevant if you want to support API level 7 or lower. In this case this limitation forces you to take special care when using foreign keys within tables. Since databases on Android are usually way less complex than those of enterprise projects this might not be as bad a problem as it sounds. But still, you have to be careful. Of course being careful is never wrong :-)

For more information on how SQLite differs from other database go to the SQLite website.

Of course what is not different from other SQL Database systems is the use of SQL to create tables, and query and update them. And of course SQLite is relational – that is, you deal with tables which store your data and the results of your queries also take the form of tables.

Where are those database files on Android?

As I have mentioned, a database in SQLite is more or less simply a file accessed through the SQLite API. In Android these files are by default stored within the

/data/data/<package-name>/databases

directory. Thus if your package is called com.grokkingandroid.android and your database is called “sample.db” the actual file would be /data/data/com.grokkingandroid.android/databases/sample.db.

Keep security in mind

As usual in Android the access rights of the database file determine who can use your database. If you follow the standard way presented in the following posts of this series, your database file will be located within the private directory of your app. This means that your app owns the database file and no one else can access it. Even using the other less common ways to create the database you can only grant access to the file. Thus others can access all of your database or nothing. There is no middle ground.

Still: You should never rely on data being safe from prying eyes in the database. Any sensitive data should be encrypted. Very sensitive data should not be stored on the device at all. Keep in mind that if the device gets lost, any misbehaving finder of the device can gain access to the database file as well as to your app. On a rooted device all files can be read. Apps like SQLite Editor make it easy to read even sensitive data – if they are not encrypted:

SQLite Editor showing the two databases of the contacts app

SQLite Editor showing the two databases of the contacts app

In cases where data privacy is of utmost importance, you have to revert to secured services or force the user to enter a secret every time before encrypting and storing the data or reading and decrypting them respectively.

Android differs from the standard Java way

Apart from SQLite’s own peculiarities there is also the way Android deals with this database. First of all SQLite is an integral part of Android. Every app developer can rely on SQLite being present on an Android system. Though which version of SQLite is dependent of the SDK which the device uses. – which of course is a good thing, since SQLite is developed actively and future Android versions should make use of those improvements.

The biggest Android-speciality of course is how Android treats the database. Android doesn’t use JDBC. And so also no JDBC driver for SQLite. This means that you are stuck with using SQLite the Android way or using another database which you have to include in the download of your app (though I see no need for any other database). It also means that you have to learn a new way to deal with databases. Any prior JDBC-knowledge is of no use in the Android world. The rest of this series will be about the special API Android provides to deal with SQLite in your JAVA-code.

Lessons learned

You have seen why Google chose SQLite as the underlying database for Android’s apps. It has many advantages, most of all it’s low memory footprint and it’s ease of use.

Furthermore you learned about how SQLite differs from most other relational database systems and what implications this might have.

With this knowledge you are well prepared to start using SQLite. In the next installments of this series I’m going to show you how to create the database, how to insert, update and delete data and how to query those records. I’m also going to post about SQLite’s full text searches feature and how to use it.

Disclaimer: This post contains a link with my Amazon.com referral ID. For each sale this provides me with a small commission. Thank you for your support!

Two Days at the moosecon Conference

This year the German IT trade show CeBIT tried something new: A conference for mobile developers, called moosecon (mobile operating system conference).

The conference lasted three days, of which I was present at two, Wednesday and Thursday. Here’s a short recap of the talks, I visited.

Wednesday – March 6, 2013 / day one

Thanks to the German railway system I was late. Nearly one hour later than expected. Thus I missed much of the first talk of the conference. And to make matters worse, the conference organizers decided to change the schedule.

HTML5 for the mobile web – Firefox OS
Chris Heilmann, Mozilla

The train delay and the reorganization both resulted in me missing most of Chris Heilmann’s talk about Firefox OS. From what little I could hear of the talk, it probably was the most interesting talk of day one. Especially since I am very interested in Firefox OS.

Those that follow me at Google plus know that I hope for FirefoxOS to become a viable competitor to iOS and Android – even though I remain sceptic of the chance to get there. I think it can only be good for innovation in the field if there is a bit more competition and if there are more open players. I am an Android developer and intend to stay one, but this doesn’t mean that I might not have a look at other systems.

Right now I mostly despise HTML5 apps on Android – simply because they do not fit. They often lack the necessary visual integration into Android and just do not feel right. That’s not too surprising, because right now most apps, if not all HTML5 apps, are created to save money while deploying the same app on multiple platforms. That’s something that simply doesn’t work too well. It has been a problem for Java apps on the desktop for years and it’s no different for HTML5 – so I guess it’s not something that will just vanish when HTML5 gets more mature, it’s API more stable and unified across browsers and so on.

Nevertheless I think there is a place for HTML5: For apps within a browser or if HTML5 apps are first class citizens of the OS as in Firefox’ case. In the latter case the problems that apply to webapps on Android are simply no problems, because all apps are webapps – with probably some kind of standard look & feel as well. Performance problems though might remain.

What I heard of Heilmann’s talk centered mostly around Web-Activities. Those more or less resemble intents. Google had introduced a proposal of Web-Intens before – but from what I understood at the conference, Google doesn’t use those any more and both now work together on Web-Activities (though this was a bit vague).

I still haven’t seen Firefox OS in action and if Chris has shown a live demo I must have been to late for it. But from this talk, I still consider it to be an interesting approach.

If you want to know more about developing for Firefox OS, visit Mozilla’s developer site for Firefox OS.

Effects of Firefox OS
NN,Telekom

Someone from Telekom’s management replaced Martin Kurze, who got ill. I didn’t get his name, but he was pretty high up. Given that he was management it was surpirsing that his slides were the worst ones presented. Whatever you can do wrong on a slide, you could find it here. But apart from that the talk was more interesting than I had expected.

He outlined why the Telekom is supporting Firefox OS. Purportedly because Telekom is all for openness. He made a big fuss about HTML5 and that this is an open standard and what not. Yes, it is and that’s what I like about it as well. But in the case of Telekom I guess it has more to do with them not wanting Google, Apple or Microsoft to be the only ones profiting.

Be it as it may, this carrier as well as many other carriers is supporting Mozilla to create another competitor and to keep relevant and get a share of the revenue. While I couldn’t care less who get’s the biggest piece of the cake, it could prove important for Mozilla in getting some traction – especially in markets in which customers are still using feature phones by a large margin (Telekom for example starts with handsets in Poland).

Successful Inhouse Enterprise Apps
Patrick Blitz, Weptun

This talk centered mainly around two aspects: Security and Connectivity. The talk was too high-fly for me to really like it. Nothing wrong with giving an overview. But moosecon is a developer conference. And as such I would have liked to see some remarks about difficulties and problems in implementing each of the solutions.

Maybe he should have sticked to just covering security. After all connectivity is a problem common to nearly all apps and thus not specific to in-house enterprise apps.

Enterprise apps nearly always have to deal with very sensitive data. Data that has to be kept private – no matter what. I really would have liked to hear more about that.

The bad audio situation didn’t help the talk either. Not the fault of the speaker who spoke clearly and articulate, but of the conference setup. More about that later on.

I think a bit more in-depth coverage of what the biggest problems are (from a developer point of view) would have helped this talk.

Creating Backends in Minutes
Lutz Kohl and Philipp Michel, Apiomat

The speakers presented backends as a service (BaaS) in general and exemplified the key points with apiomat, the solution of their company.

Obviously the speakers had an interest to present BaaS in the best possible light – and they did a good job at this. There are very good reasons for using backend services in the mobile environment. Their main point was that it reduces time to market, that it helps safe costs and that you do not have to care about getting the necessary amount of power and of getting this right. Time to market is probably correct, depending on the flexibility of the BaaS provider. I also think that it’s difficult to estimate the necessary computing power and that for many projects it’s an unnecessary burden to have to think about load balancing, redundancy, failover solutions and what not. So far I’m in the BaaS camp.

But I think the speakers purposefully underestimated the complexity around REST – which will remain independent from using a BaaS solution or a selfmade one. Thus I do not believe their cost estimate at all – but well, of course they were a bit biased :-) Granted, BaaS probably is cheaper, but the difference is much smaller than presented here.

They showed how to use apiomat, how to generate code from their website, where to create custom business logic besides simple CRUD-logic and how to integrate apiomat into your app. Both speakers did a good job, but some stuff could have been a bit more detailed. Also the dashboard and any reports would have been interesting.

Nevertheless BaaS solutions are interesting and can help your project siginificantly. Apiomat is a German solution targeting the European market, so maybe they are the right solution for you. Which BaaS provider to use comes down to a business and a trust decision. The latter is very important since BaaS requires a trustworthy partner. And don’t forget the privacy aspects as well. At least we Germans are very sensitive when it comes to this.

Push Notifications
Benjamin Broll, Little Postman

Benjamin talked about push notifications and how complex this can get – especially if you want to use push for different target platforms. The latter is made worse because each platform has it’s own notification model and each provider handles communication between your backend and the notification delivery service (e.g. Google Play Services for Android or Amazon Device Messaging if you care about the Kindle Fire). He detailed the problems you have to deal with if you want to do so on your own. Well, of course he was on a mission as well – but this part of his talk was really good!

He also stated reasons why push is a good solution and that it might help user satisfaction – especially if you find innovative uses for push – the examples he gave were also interesting to hear.

So far so good. But why not show how to do all that with Little Postman? After all, that’s his company and there’s nothing wrong to present your stuff if your general points are presented in a more or less neutral fashion. I think he missed an opportunity here to drive home the message, that Little Postman could be the solution of choice for you.

Overall impression of day one

I have heard some nice talks but obviously missed a very large part of the most interesting talk. All in all it was too little code and often too high-fly for a developer conference.

But the worst thing was, that it didn’t get the attention that is so important for conferences. Attendee numbers were quite low – especially in the closed area. So one of the great by-products of conferences – being able to meet people you know via the many social channels as well as to network with other devs – was nearly completely missing for me.

Audio quality also was a big problem – at times nearly unbearable. The sound level at trade shows is always very bad. But in this case the open and closed stages were too close to each other, which sometimes made listening unnecessary hard.

Wednesday – March 7, 2013 / day two

I was on time – great. But there had been a shuffling of talks once again. The first two talks at the open stage were swapped. Thus I couldn’t hear the Google TV talk I originally had planned to go to and instead listened to a white-collar talk I hadn’t had on my agenda.

Cross Platform for White Collar Workers
Marcus Ross, Zahlenhelfer Consulting

Marcus is developer and project manager – but in this talk he was all project manager. The title of the talk says it all: It was no technical talk.

Obviously Marcus thinks much more of HTML5 apps as a cross-platform solution than I do. He believes that they can be a good fit for apps, that must run on multiple platforms. He mitigated this by saying that it depends on the requirements, but still…

According to Marcus, often some kind of hybrid is needed where you access certain hardware features via a wrapper API and otherwise use HTML5 to develop your app. Another point of Marcus was, that unless you are doing in-house stuff or cannot use the app market for business reasons (e.g. for publishers the Apple app store often is no option), you should always use at least some kind of wrapper to market-enable your app.

I think though, that this is risky: Putting your app on the platform specific appstore might make marketing sense, but it also sets certain expectations of the customers. I think HTML5 apps should stay on the web, be clearly recognizable as web apps and as such should use a standalone UI that doesn’t try to mimic the native UI. Marcus obviously disagrees and showed samples of apps that try to resemble native apps as closely as possible. Well being an Android native developer, it’s kind of my duty, to disagree :-)

If you wonder how this fits in with my Firefox OS hopes, keep in mind that on Firefox OS it’s a completely different story – there HTML5 is native! And I wouldn’t recommend to use a Firefox OS app on Android within some native wrapper. I have no problems with them though, if they run within a browser!

At the end the organizers started talking at the second stage – which caused many (including me) to leave this stage. But then the talk actually didn’t begin for another five minutes. Sorry, but this shouldn’t have happened. The organizers should have been more careful. It simply was not fair to Marcus.

Ugly thruth about HTML5
Robert Virkus, Enough Software

This talk was some kind of counterpoint to the previous one. Robert prefers native. And it’s not just what I’ve written above, but there are technical reasons why cross-platform is not as cross-platform as management thinks. Most platforms (Microsoft’s Windows Phone OS and Mozilla with Firefox OS being two exceptions) use Webkit as the default rendering engine, but that’s just one part of the story. When it comes to Javascript – and you will need to use Javascript – each vendor uses its own engine. And even worse: Webkit is not the same everywhere. There are tons of compile time flags and Android uses different ones then iOS. Thus you can use some stuff on Android which isn’t available on iOS and vice versa.

Than he mentioned the uncanny valley. That’s a robotics theory stating that when humanoids get more and more close to actual humans people at first like this, until it suddenly changes and people start to strongly dislike those robots – until approval rises again when the humanoid is nearly indistinguishable from a real human.

He applied this uncanny valley theory to mobile apps. People will dislike your app if it tries to be like a native app, but fails to actually deliver. Thus his advice for any HTML5 apps: “Don’t mimic the native UI – use an HTML5 UI”. Couldn’t agree more!

BTW: That’s the reason why HTML5 works for games that do not need native speed. Games most often do follow their own style and thus do not mimic the native UI anyway. And since games never did, customers won’t wonder about this. Instead they expect games to be different. In my opinion games are thus currently the only real option for HTML5 apps.

Mobile Market News
Sacha Pallenberg, MobileGeeks

Well, i don’t know. I’m no big fan of him. But he definitely is a great speaker and he knows his stuff (mobile hardware) very well. Thus this talk was indeed very interesting. His talk was lively and it was obvious that he really enjoys his field and also talking about it. His talk was hampered by severe technical problems (the beamer going off every now and then for roughly two/three minutes) but he managed to work around that effortlessly.

First he talked about SoCs. Something I’m not much interested in.

Interesting though his take on the battle of mobile operating systems and if competitors to iOS and Android can play any significant role. In short: He’s not very optimistic about any of the other platforms – with the exception of Windows Phone. One point for FirefoxOS is that it has the backing of many carriers, but he doesn’t believe that it will help them that much.

What took me totally by surprise was his statement, that Nokia managed to keep it’s ship afloat because of its Windows Phone transition. Huh? Right now I still think this strategy is not working too well for them. But let’s wait what the future might hold. Predictions in this area are not worth too much anyway :-)

Lessons Learned from Prime Guide
Markus Junginger, greenrobot

Finally two Android related talks. Markus talk about Prime Guide – an Android only TV programme app that I highly recommend and use myself – came first. His talk contained some interesting surprises. Lessons learned are always great and probably should be covered more often (on conferences as well as on blogs or in magazines). Why not learn form others?

The Prime Guide team took great care to deliver an outstanding Android experience – a necessity to compete in the crowded TV-programme market. And it can be seen: As a user of this app, I can confirm that it indeed performs well and looks great. The good ratings of the app are another proof that they did a good job.

The devs made heave use of libraries or created some while developing the app. Something Markus recommends highly to all Android devs. But even with using libraries, the app took still way longer than expected – not least because its developers had to move to customer projects and couldn’t work continously on the app. Markus estimated the total amount for the app was more than one person year.

Especially fragments gave them headaches. To quote: “Fragments are one of the most difficult APIs” in Android. Especially together with multi-threading and funny (or rather not so funny) life-cycle issues.

Prime Guide is a good example for why BaaS makes sense. They have two big peaks when it comes to backend hits: In the evening when people actually start to watch TV they use this app the most. From the graph presented it’s an enormous spike and to cope with that, you definitely have to use a cloud based service – or use a set-up that idles away most of the day. The second spike comes from when the server downloads and processes TV programme data.

In his talk, Markus mentioned some problems with app engine. One of them stuck with me: When they started out, AppEngine offered no SQL database. And according to Markus “that’s not cool” at all (so much for the NoSQL rage) – but instead caused them to adapt the data model to app engines’ special needs.

The thing though, that surprised me the most was his statement, that they shouldn’t have published the app for all device categories at the same time. Since I think this app is extremely well suited for tablets, I asked him if they wouldn’t have been missing out had they done a phone only app first. Markus states that they could have released the app much earlier had they made a phone only app. I guess there is no arguing about that. He also states that when they started out Android tablets had not been as wide-spread as nowadaays. Granted, but I still wonder.

Would their initial rating (4.6 in the first week) have been as good? Wouldn’t many have complained and demanded a tablet version? Which might have caused them to rush one with potential implications for the overall app quality. Finally a tablet later strategy might have lead to some serious refactoring when adding the tablet-related aspects later on. With probably even more complexity and headaches. I don’t know. Markus has way more experience than I have, so I really would like you to chime in. What do you think about releasing for the phone first? And is this still a viable strategy – now that many more tablets are in use? Please let me know on G+ or in the comment section.

Oh, and here’s one last but important advice from Markus: Release early! Don’t wait till it’s perfect! Users might have different needs anyway (in their case for example they wanted more channels within the app).

In short: Great talk!

Edit: After reading my draft, Markus send me some clarification about this: In this clarification he suggest to only offer the most essential functionality for tablets right from the beginning and to add more later on. Do not waste time with every detail on every screen for all three versions (Google TV, tablets and phones) but concentrate on phones and only for some especially central screens on tablets. Even with this clarification I still would like to hear your thoughts on this in the comments!

AB-Test Library for Android
Hasan Hosgel, Immobilienscout24

In his talk, Hasan Hosgel presented his library CustomersChoice, that you can use to enable AB-Testing within your apps. It’s an open source Android library and the project page of CustomerChoice is hosted on github.

Hasan first stated why he created it. The point is that product managers often have no clear idea which features are really useful or how to present those features. Usually you create a short user test to find out, but often you still don’t get a clear picture. That’s where this library comes into play.

While ImmobilienScout24 (Hasan’s employer) can afford customer surveys and user tests, small shops or indie developers sure can’t. Thus this library is even more useful.

After this he showed how to use the library. You only need a few lines of code to choose a variation and to report a success – if the user found and used the feature you test.

Configuration needs a bit more code but is still pretty straightforward. Configuration can be done in multiple ways. Either in code or by a JSON definition that the library can download from the web, read from the SD card or get from a resource definition within the app. Here you define the variants and their variations. A variant is one feature you AB-test. A variation is one specific implementation of this variant. So if you want to test which of three colors is the best this would be one variant with three variations.

Each variant has a name you later use in code. They also have optional start and end dates to scope the test. And you can set the ratios between the variations – the default being a uniform distribution of course.

Finally Hasan showed the library in action and it’s integration into his code. You can also download a demo of Customer’s Choice to have a look yourself.

My only beef with this library is it’s name. It suggest a conscious decision by customers about which features to implement in which ways. Which generally is no good idea. You should listen to customers, of course, but which features to implement and especially in which way should be your decision based on user goals, usability concerns, the direction you want to move forward in and the general style of your app. Thus I think CustomersChoice is a misleading name.

So to clarify: This library let’s you find out which possible implementation works best for your user base. Exactly what we sometimes need.

Good talk and an interesting library. I suggest to have a look at it.

How Paypal uses Open Identity
Tim Messerschmidt,Paypal

Now, to be honest: If Tim hadn’t been in my Google plus circles I never would have watched this talk. Paypal is not my most liked service on the web. Apparently I’m not alone with it, because Tim tried to destroy any doubts about using a Paypal solution :-)

First Tim explained the concept of identity within his talk. It’s mainly about authenticating a user. All those “Log in with Twitter” buttons basically allow you to use one account to access multiple websites.

And here is where Paypal comes in. For shopping sites you may not want to use your Twitter account but a more reliable partner that either already has your credit card information or which you trust enough to hand over your payment information.

Paypal uses OpenID Connect which, according to Tim, is much easier to use for us developers than plain OAuth 2 – even though it uses OAuth under the hoods. He explained that OAuth has developed in a direction where you basically need a custom implementation all the time without being able to leverage code reuse. Something that OpenID Connect seems to solve. Whether that’s true or not, I do not know – but I know that OAuth has a reputation of being a mess.

He also showed the different levels of information clients can get from Paypal. As usual the user gets a short list of what is offered by the provider (here Paypal) to the site. In Paypals case this ranges from just a confirmation of the name and the email address to the real-world address of the user to his age information. Finally Tim concluded his talk with a short demo.

Paypal might actually be the appropriate solution in some situations. But for now the only important thing for me is to know that it exists – should I ever have a need for it.

Overall impression of day two

Apart form two things this day was much better. Sound problems were not as pressing – especially since in the afternoon only one stage was used. The problem with the beamer – well this can happen. Not too much of a problem – though they were lucky that it happened while a seasoned speaker was on stage. Totally unacceptable was the early opening of the second stage while a speaker was giving his talk on the other stage. Given the sound condition it was no wonder that many people thought the next talk was starting.

Apart form the first talk, this day was more technical – which obviously is more to my liking. And this day I also met people I knew. I’ve met Hasan Hosgel at last years Google devfest in Berlin and together with others we stayed at c-base for quite some time in the evening. It was nice seeing him again – though I prefer the c-base atmosphere any day! I hope for another devfest this year. I also knew Markus Junginger, Matthias Friedrich (no speaker) and Tim Messerschmidt from Google plus. Great meeting them as well.

How the moosecon should change

I think the moosecon has a future, but it must improve in some areas. It should be more technical and more dev centric – or offer two slots: One for devs and designers and one for management.

Having mentioned designers: I wonder why they aren’t invited as speakers to these events? The design (as well as the usability, which is something completely different) plays an important part in the success of an app – still it’s ignored way too often. I’m a dev, I have no talent at all for design, but even I notice apps that are either too complicated to use (bad UX) or simply visually too off-putting to use. The one problem here of course is that UI and UX concepts of all platforms are vastly different. But so are the programming models.

I think speakers should be instructed to give a technical talk (unless the conference offers the two slots I mentioned above, in which case I only speak for the dev slot). To concentrate on those aspects that are most interesting to fellow devs like problems encountered and tips how to deal with them. Or talk about how to use your libraries/products, how to integrate them.

In general the conference must attract more people. The organizers must concentrate on that. Good talks are one way to achieve this, but not the only one. Maybe more hands-on stuff would help. Some kind of app-dev-contest, hackathon or what not. Or offer some power workshops. It was simply too little content.

Another possibility would be to only use two days but more stages. Given that the early as well as the last talks were not visited well it might also be worth to consider reducing the overall time on stage and offer other things like workshops afterwards.

As a final note: The catering was excellent. Thanks!

Adding ActionViews to Your ActionBar

As you have seen in the previous tutorials about ActionBarSherlock and the ActionBar, you can add action items easily and they show up either in the ActionBar itself or in the overflow menu.

But so far all you could add were normal action items. And those consisted either of icons, of text or of a combination of both – depending on the available space and of the way you configured the items to show up.

That’s not always sufficient. Sometimes you would like to display a custom layout. And that’s what ActionViews are for.

What are ActionViews

Action views allow to display arbitrary layouts instead of the usual icons or texts. They were introduced in Honeycomb together with the ActionBar.

Of course the available place for your layout limits your possibilities. Since – by a large margin – most Android devices are phones, your layout should take this into consideration.

With Ice Cream Sandwich ActionViews were improved further. Since then Android does not always display them fully expanded but allows for a collapsed mode as well. In this mode ActionViews show an icon as usual and only when the user clicks on the icon does it expand to the full layout.

When to use ActionViews

Basically you use ActionViews when you need to replace the icon with something else or when you need a more interactive widget.

Android itselfs comes bundled with the SearchView that adds an EditText widget for search. I will cover this widget in the next section.

Another common use case is to replace an action item with a progress indicator when the action is bound to last longer. Most often this is used together with a refresh action item.

Using Android’s SearchView

Android comes with the SearchView as the only bundled implementation of an ActionView.

I covered all you need to know about searching on Android and search suggestions in previous tutorials. Here I will cover only how to make use of the SearchView.

Let me first show you some screenshots:

Collapsed Searchview showing only the search icon

Collapsed Searchview showing only the search icon


Expanded Searchview showing the EditText field together with the search icon and the search hint

Expanded Searchview showing the EditText field together with the search icon and the search hint


Expanded SearchView with entered text

Expanded SearchView with entered text

The first shows the action bar with the search icon – thus the action view is in collapsed mode. The second screenshot shows the view after the user has clicked on the icon. It expands to an EditText widget together with the search hint of your searchable configuration. The microphone symbol is also the result of the search configuration file. The last screen shows the EditText widget after the user has entered some characters.

If you have added search capabilities to your app, getting the SearchView to support this is pretty easy. All you have to do is tell it about the search configuration. For this you need to get a SearchableInfo object from the SearchManager and call setSearchableInfo() with this object on the SearchView object used for your ActionBar. Well for me code is often the best explanation, so here is what you have to do:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
   getSupportMenuInflater().
         inflate(R.menu.activity_actionview, menu);
   MenuItem item = menu.findItem(R.id.actionView);
   SearchView searchView = 
         (SearchView)item.getActionView();
   SearchManager searchManager = 
         (SearchManager)getSystemService(Context.SEARCH_SERVICE);
   SearchableInfo info = 
         searchManager.getSearchableInfo(getComponentName());
   searchView.setSearchableInfo(info);
   return true;
}

You should understand most of it from my previous tutorial on ActionBarSherlock. New are the lines 6 to 11. These are where you add your search configuration to the SearchView.

As you can see in the code above, I use the SearchView together with ActionBarSherlock. ActionBarSherlock added a SearchView with its 4.2 release. As a deviation from ABS’ normal API level 7 support, the SearchView only work from API level 8 onwards. The reason for this is that the SearchableInfo interface was added with API level 8. So a support for a SearchView prior to that makes no sense.

The version in ActionBarSherlock’s 4.2 release had some problems with search suggestions. These were fixed by Matt Kranzler’s accepted pull request to ABS. But this fix is currently only available in the dev branch of ActionBarSherlock.

Update: With the 4.3 release of ActionBarSherlock suggestions now work. So if you want to use them, you have to include ActionBarSherlock 4.3 (or any follow-up releases).

The next screenshot shows the suggestions provider at work with ActionBarSherlock’s dev branch fixes on a 2.2 device:

Suggestions working in ActionBarSherlock when using the dev branch

Suggestions working in ActionBarSherlock when using the dev branch

Be very careful, if you use this branch. After all the current development is taking place here. It’s not yet finalized for production!

A custom ActionView

As mentioned you can also create arbitrary action views. You have some options to do so:

  • You can link to a layout file from within your menu.xml
  • You can set the layout when the action item is clicked
  • You can write a custom View implementation

I do not cover the last one. That’s because it’s the least likely solution for you and also because I haven’t yet covered how to create custom views in Android in this blog.

So let me show you how to use the first two.

Linking to a layout file

In this case you create a layout file and point to it directly from within your menu xml file:

<item 
   android:id="@+id/actionViewLayout"
   android:showAsAction="ifRoom|collapseActionView"
   android:icon="@drawable/ic_action_add"
   android:title="Add"
   android:actionLayout="@layout/activity_actionview_edittext"
/>

In line six you can see how the layout is referenced directly from within the menu item definition.

You still have the option to show it in expanded or in collapsed mode right from the outset. Line three in the xml snippet above uses a collapsed mode at first. The difference becomes obvious in the next screenshots. The first set shows the item in collapsed mode first. When you press the add item, Android expands the layout and moves all other action items into the overflow menu.

The add Actionview in collapsed mode

The add Actionview in collapsed mode


Add ActionView in expanded mode

Add ActionView in expanded mode

If you use the layout expanded all the time, it’s present all the time and takes up the place it needs. All other action items are visible – as long as some place is left for them. That’s what you see in the next screenshot. This option is the most space-constrained option you have. If your ActionView is always expanded, you probably have not much room left for any other action items. That’s the reason I use a landscape screenshot. So make sure you use the value ifRoom for the android:showAsAction attributes of all the other items – and to limit the action view to as little space as absolutely necessary.

ActionView expanded right away

ActionView expanded right away

To use the expanded view all the time you simply have to remove the collapseActionView value and the pipe symbol from line 3 of above’s xml snippet.

Of course it depends on the use case at hand and what your layout is, but I think this option generally is best used with an expanded layout all the time. Otherwise users might get confused by the disappearing action items when they expand the layout. And users might not know that they can use the back button to collapse the view again. If you plan to expand the layout on an action item click you’re probably better off with the option of the next paragraph.

Setting the layout when the user clicks the item

This option combines both methods of the former paragraph. Once again two screenshots demonstrate best what I am talking about:

Refresh ActionView in collapsed mode

Refresh ActionView in collapsed mode


Refresh icon replaced by ProgressBar spinner

Refresh icon replaced by ProgressBar spinner

The first screenshot shows the refresh icon as a normal action item. The layout file looks like any other menu item:

<item
   android:id="@+id/progress"
   android:icon="@drawable/ic_action_reload"
   android:showAsAction="ifRoom"
   android:title="@string/progress"
/>

But as soon as you click the refresh button, Android replaces it with the progress spinner. That’s because I set an action view in reaction to the action item click. The first code shows the onOptionsItemSelected() method in which I react to the item click:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
   if (item.getItemId() == R.id.progress) {
      new DummyAsyncTask().execute((Void[])null);
      return true;
   }
   return super.onOptionsItemSelected(item);
}

The AsyncTask is a sample implementation showing you how to change the action view values:

private class DummyAsyncTask extends 
      AsyncTask<Void, Void, Void> {

   @Override
   protected Void doInBackground(Void... params) {
      // simulate doing some time-consuming stuff:
      SystemClock.sleep(2000);
      return null;
   }
   @Override
   protected void onPostExecute(Void result) {
      super.onPostExecute(result);
      ActionViewActivity.this.mProgress.setActionView(null);
   }   
   @Override
   protected void onPreExecute() {
      super.onPreExecute();
      ActionViewActivity.this.mProgress.
            setActionView(R.layout.activity_actionview_progress);
   }
}

As soon as the work is done and the new values have been downloaded, you simply set the action view to null again – in the code above I do this in the onPostExecute() method.

As you can see it uses an expanded mode – but only for the time, the user actually needs this view. Do not use the value collapseActionView in your menu item definition. Otherwise the layout expands on the left of the ActionBar and not in place of the icon!

Sample app

You can find the source of a sample app demonstrating all this on bitbucket. I’m more than happy if you spot any problems with the code and provide a pull request. You can also file an issue on the project page.

Lessons learned

In this tutorial you have seen how to make use of ActionViews. Very useful is the SearchView – thus I detailed how to add this to your ActionBar and how to link it to your search configuration in this post.

You have also seen that in the current 4.2 release of ActionBarSherlock SearchSuggestions are not yet working correctly. But thanks to a fix those will be part of the next ABS release.

Finally you learned how to create an ActionView on your own, though use cases for this are limited. Probably the most common one is replacing an update icon with the progress spinner widget.

Subscribe to RSS Feed My G+-Profile Follow me on Twitter!