Wednesday 27 April 2011

Integrating Google Analytics into Android

One of the many things on my development list for the current Android projects I'm developing has been to integrate some form of user tracking/feedback functionality into the application.

Ill show you how I went about integrating Google Analytics into a sample application explaining some of the reasons and decisions I took along the line.

API's/Library

After a quick Google and a little bit of reading there seems to be a serious lack of available Google Analytics API's for android. One alternative is a paid Analytics tool from usermartix but since its not free it doesn't really help me for the example so I'm sticking with Google's own Analytics SDK for Android.

Prerequisite

I'm going to presume you have eclipse or a similar IDE installed with the Android SDK and IDE plugin set-up and installed. Installation instructions are available in the getting started section of the Google Mobile SDK docs.

For this example the code will work on Android 1.6 and above (a.k.a Donut) All code can be found at my GitHib repository @ https://github.com/jamesemorgan/AndroidGoolgeAnalyticsDemo


Getting Started


1) First create a new "Android Project" in Eclipse giving your application a name, package structure and specifying Android 1.4, API level 4.

If you haven't create an Android Emulator yet, plenty of information can be found on-line but the best way is to use the AVD manager which gets installed with the SDK and can be launched directly from eclipse.

2) Download the Google Analytic SDK, unzip it and place the jar in your libs folder or simply add it to your build path of the project as seen to the left.

3) Add the following lines to your AndroidManifest.xml file in order to enable to use of the Internet when you deploy your application. An exception will be thrown if not.









Creating Your Abstract Activity

I've done this in other projects and it simply encapsulates your Google Analytics code in a super class. This just means you can make all your other activities extend this class and thus reduce the need to for duplicate Analytics code in ever Activity you want to track. Since Android is based on the activity model it seems like the most appropriate solution for encapsulating this logic. 


public class AbstractAnalyticActivity extends Activity {

 private GoogleAnalyticsTracker tracker;

 @Override
 protected void onCreate(final Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // Get and set the Google Analytic tracker instance
  setTracker(GoogleAnalyticsTracker.getInstance());

  // Get application shared preferences
  final SharedPreferences preferences = getSharedPreferences("SomeSharedPreferenceKey", Activity.MODE_PRIVATE);

  // Get your preference key for enabling google analytics
  final boolean enabledGoogleAnaltyics = preferences.getBoolean("PREF_GOOGLE_ANALYTIC", true);

  if (enabledGoogleAnaltyics) {

   // Arg1: Your tracking ID
   // Arg2: How often your tracking events get dispatched to google, set to 20 seconds
   // Arg3: The activity to track
   tracker.start("UA-XXXXXXXX-X", 20, this);
  }
  else {
   // Stop the tracker if not enabled
   tracker.stop();
  }
 }

 private void setTracker(final GoogleAnalyticsTracker tracker) {
  this.tracker = tracker;
 }

 public GoogleAnalyticsTracker getTracker() {
  return this.tracker;
 }
}


Above is the class I created to encapsulate all Google Analytic logic. 

  • First create a GoogleAnalyticsTracker variable, with a public getter and private setter thus to only allow subclass's the ability to retrieve the tracking class. 
  • Secondly, as with most Android Activities you must override the onCreate method which is where I place all set-up code for the Google Analytic tracker. 
  • Replace UA-XXXXXXXX-X with your Google Analytics account ID.  Again plenty of instructions/guides online can be found on how to do this.
  • In addition to any Analytics code I have also included an example of how to retrieve  application user preferences in order to give the user the ability to disable tracking if they wish so. (Lines 13-16) I believe this should always be the case when tracking a users movement you should always give them the option to not be tracked. I believe visibility and trust is key to a successful user/developer relationship.
Define your Activities XML


For this example I simply have four buttons on my screen each one symbolising how a user many navigate between different sections of your application. One of the recommended design practices is to create an opening dashboard. Each button is defined as seen below. Notice the onClick Handler, we will use this later for tracking which parts of the application a user navigates to. Simply modify the default main.xml file created for you by eclipse and add the buttons shown below.









 

 
  
  
 

 

  
  
 



Create your Activity

Next step is to create the activity you want to track, for the purpose of the this example I've  called mine AndroidAnalyticsDemoActivity and extends the Abstract Activity mentioned earlier. Add your onClick listeners as defined before, and ensure you call the super class onCreate method or an exception will be thrown.
In order to track an event, I simply retrieve the tracker from the parent class and set what page view I want the tracking to be registered as. I've done this for each button declared in the main.xml file mentioned earlier.

Don't forget that Google Analytics is 24 hours behind and will not show you any analytics data straight away. Don't be surprised if your newly created account doesn't show anything straight away.



public class AndroidAnalyticsDemoActivity extends AbstractAnalyticActivity {

 @Override
 public void onCreate(final Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // Set you main view, i.e. your GUI xml file
  setContentView(R.layout.main);
 }

 public void onStatsClickgetTracker().trackPageView("/DashboardStatsActivity");
 }

 public void onGroupsClick(final View v) {
  getTracker().trackPageView("/DashboardGroupsActivity");
 }

 public void onFriendsClick(final View v) {
  getTracker().trackPageView("/DashboardFriendsActivity");
 }

 public void onHomeClick(final View v) {
  getTracker().trackPageView("/DashboardHomeActivity");
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  // Stop the tracker when it is no longer needed.
  getTracker().stop();
 }
}

Conclusion
Google Analytics provides a quick and simple way of tracking application views and events inside your Android application. I've only shown you how to track page views but as with most things, a plethora of information is available on the Internet about this useful and intuitive API.

Sunday 17 April 2011

Contract First Web Service with Spring Web Services 2

Recently I've needed a simple SOAP based WebService which will be called from an Android Application. Below is an example of using the power of Spring WebServices 2 to create a contract first WS in a relatively short period of time. I chose to use Contact First due to the benefits and flexibility it brings on all levels, Spring Source also recommend a Contract first approach to reduce the XML and Object mapping infeasibility and inflexibility issues that commonly arise.

Spring-WS website: http://static.springsource.org/spring-ws/site/

Along side spring-ws sits spring-ws-test which makes it very easy for both client and server side testing and reducing alot of boiler plate set-up you may have to make when attempting the test web service out the box.

Before I start you can grab all the source code related to the post from my GitHub account.
Simply navigate to the below and clone or fork the project:


https://github.com/jamesemorgan/LoginDemoWebService

Creating your Contract:


Below is the XSD I created before writing any code which I use as a starting point for the following example. It simply defines the request and response payloads plus any additional complex object types I use. The most complex being a GUID with a matching regular expression to enforce validation and make up. The good thing about spring is it takes care of validating and enforcing incoming request payloads so you don't have to.




 
  
   
    
    
    
    
   
  
 
 
 
  
   
    
    
   
  
 
 

 
  
   
  
 



JAXB Object Creation:

I use the JAXB compiler to interpret and create my Incoming and outgoing request payloads.

This can be seen below:
Navigate to you XSD.
cd .\src\main\resources\webService
Invoke JaxB and specify the XSD location, the package to place created objects and the directory to put them.
xjc incoming-android-login-schema.xsd 
-p "com.morgan.design.demo.login.ws.generated" 
-d "../../java/"

Defining you Spring Endpoint and Jaxb Marshaller:


Below is my spring context configuration file, all I am doing here is defining the actual incoming WS location and applying the needed and marshallers to convert the object to and form my JAXB classes, plus specifying additional request and response payload validation.




 
 

 
  
 
 
 
 
  

 
 
  
   
    com.morgan.design.demo.login.ws.generated
   
  
 

 
 
  
  
  
   
   
   
  
 


Creating your EndPoint:

I've chosen to go down the annotation driven approach simply as this is what I'm familiar with, but as with all Spring products the choice is yours and Endpoint creation can be done by either XML or Annotation configuration. If you choose to go with a annotation driven route, all you need to do is add the following to your spring config and ensure the correct packages are being scanned:


  



Firstly you need to annotate your class with @Endpoint to specify your class is ready for accepting incoming web service requests.
@Endpoint
Secondly create your method and specify the incoming payload with @RequestPayload (in the example below this is a Jaxb generated class).
@RequestPayload
Next annotate your method with the incoming namespace and request type.
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "LoginRequest"
The example method below has two arguments, firstly the marshalled incoming object and plus an additional argument of org.jdom.Element, which will contain the complete incoming request which I later use to extract the raw request.
@RequestPayload final Element element
@Endpoint
public class LoginRequestEndpoint {

 private final Logger log = Logger.getLogger(this.getClass());

 public static String APPLICATION_UUID = "bcf7d786-61b3-11e0-a8cf-643150372d03";

 public static final String NAMESPACE_URI = "http://morgan-design.com/ws/schema/2010";

 @PayloadRoot(namespace = NAMESPACE_URI, localPart = "LoginRequest")
 public @ResponsePayload
 LoginResponse handleLoginRequest(@RequestPayload final LoginRequest loginRequest, @RequestPayload final Element element)
   throws Throwable {

  // Validate Login Application Code -> this could be/should be DB driven in a live environment
  if (!APPLICATION_UUID.equals(loginRequest.getApplicationUUID())) {
   throw LoginRequestInvalidClientIdException.create(loginRequest.getApplicationUUID());
  }

  // Convert element to string for purposes of audit logging etc, this is optional
  final String xml = convertPayloadToString(element);

  // Generate a new UUID, this should be saved to the DB for the current session of the client application
  final String uuid = UUID.randomUUID()
   .toString();

  // Return a login response to the client
  return createLoginResponse(uuid, 1);
 }

 /**
  * @param element the Raw {@link Element} SOAP Element
  * @return the XML in {@link String} form
  * @throws LoginRequestTransformationException
  */
 private String convertPayloadToString(final Element element) throws LoginRequestTransformationException {
  try {
   final XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
   return outputter.outputString(element);
  }
  catch (final Throwable e) {
   this.log.error("Error converting Login Request: ", e);
   throw LoginRequestTransformationException.create();
  }
 }

 /**
  * @param authenticationID a generated {@link UUID} code
  * @param responseCode the success, failure response code
  * @return a constructed {@link LoginResponse}
  */
 private LoginResponse createLoginResponse(final String authenticationID, final int responseCode) {
  final LoginResponse loginResponse = new LoginResponse();
  loginResponse.setAuthenticationID(authenticationID);
  loginResponse.setResponseCode(responseCode);
  if (this.log.isDebugEnabled()) {
   this.log.debug(String.format("Creating Login Response, Authentication Code [%s], Response Code [%s] ", authenticationID,
     responseCode));
  }
  return loginResponse;
 }
}

Creating WebService Exceptions:

Below is an example of a Spring Web Service Exception. Simply annotating your Exception with @SoapFault(faultCode = FaultCode.SERVER) and ensuring the containing package is being scanned by spring the exception will be marshalled and sent as a SOAP exception, in this case a Server Fault exception. Other exception types can be used as seen below.
@SoapFault(faultCode = FaultCode.SERVER)
public class LoginRequestException extends Exception {

 /** */
 private static final long serialVersionUID = 4850097068571927700L;

 protected LoginRequestException(final String message) {
  super(message);
 }

 public static LoginRequestException create() {
  return new LoginRequestException("A server fault has occured");
 }
}

All in all, spring web service 2 makes it very simple and quick for you to throw together web services. Once you understand the types of steps to go though when making contract first web services it all becomes alot easier and spring takes out the complex parts such as request and response validation and marshalling.

The above demo simply highlights some of the niceness you get by using SpringWS 2. All the source can be grabbed from my GitHub account. https://github.com/jamesemorgan/LoginDemoWebService

When I get abit more time I will demonstrate how to get Android to consume the above web service.

Tuesday 5 April 2011

Pencil Project: Sketching and Prototyping with Firefox

Recently I've been using a wicked new tool called Pencil Project which allows you to make quick and simply GUI Prototype mock-ups. The tool is built on top of the Mozilla Gecko Engine and runs on all operating systems which Firefox 3 runs on. It comes in two forms, firstly a Firefox plug-in which runs inside your browser as well as a standalone installer which runs like any other Desktop program. I chose to run Desktop client as Google Chrome is my browser of chose at the minute.


I initially started using it a work, replacing fag-packet paper designs with a fully fledged interactive GUI design which can be tweaked, exported and easily shown to all stakeholders who have and interest. I've now put it to use on designing not only web applications but Android GUI's and its great. 


Best features:


Tabs
Tabs is a must in my mind for applications such as this, following the direction of a lot of modern applications, the tabbed design creates an easy and intuitive way to follow your design process through the motions. 


Base Design
One of the best features it has allows for the ability to have a base design which you can then add to as new components get created. I've been using this to show GUI changes on the same screen, i.e. pop-ups appearing, interface changes depending on particular events etc. Below in an example log in screen which goes through the motions of authentication with a failure. The base design template means you can simply duplicate a tab, set the background to be an existing design and then simply make changes as you see fit depending on different outcomes.





Open Source
Being an advocate of open source its always a benefit when a tool you use is open source and freely available.


Exporting
Pencil allows you to export your document to several formats including; PNG, HTML, PDF, ODT (Open Office) and DOC (Microsoft Office).  It also has the ability to create your own exporters so you can save to any file you like, I'm not to sure if I'll ever need this as PNG, HTMl and PDF are my preferred formats for prototyping. 




All in all its a great addition which I'll be adding to my toolbox, cheers to the people at Evolus who made it.


Website:http://pencil.evolus.vn/en-US/DevGuides.aspx
Developer Site: http://pencil.evolus.vn/en-US/GetInvolved.aspx
Google Code Repository: http://code.google.com/p/evoluspencil/w/list  

Monday 4 April 2011

Who's Making The Brew v1.7

After a wet and relaxing weekend in "Sunny" Manchester, I've had a little free time to add some nice new features to "Who's Making The Brew". Most notable I've changed how the Tea Timer works, pushing all timing logic into an Android service, and abstracting away many replicated methods into Utility classes for re-use. The Tea Timer now vibrates on completion and displays a countdown time as a notification in the Android status bar. Preferences to control these features are coming in the next release.

Another Break though I have had, is the ability to view Android source code in Eclipse.

Change log includes:

---- 1.7 - 3rd April 2011 

* Fixed preference bug not showing on fresh install
* Fixed dashboard layout, icons centre aligned and all same size
* Add tea timer V2
* Added notifications and vibration
* Re-factor replicated methods in to utility methods
* Set up source files for apk
* Added Menu to Dashboard