Tuesday, 16 March 2010

Android as SOA player


There is no argue with the fact that one of the most important parts of SOA is to provide business processes combined with human interaction, meaning that an interruption occurs until a person interacts with the system by performing an action on a waiting task to make the process flow. Therefore, it is crucial to provide a medium for human interaction to accelerate the work behind the business process. No doubt that the mobile world is growning very fast providing connection options to Internet supported by GSM operators. The pattern of combining these two trends into IT structure has been used in most SOA implementations.


Whatever the target businesses of an application, it gets more attention by the users once it is supported by the mobile platform. This is why I tried to develop an Android application as a client of composite application developed in Oracle SOA Suite environment. The composite application is TranslationService mentioned in my last blog post. Briefly, it implements client of Google's RESTful service that translates any statement from a source language to a target language. Mediator component in SOA composite application's and its implementation detail is given in my last post, but Java code of Mediator's callout class is given in lowermost part. The Android application's screen design is given in Figure 1, including all of the necessary fields required by the translator client. Source text, language and target language values are prompted first, and then the Translate button is used to perform translation service call at Oracle SOA Suite side. The result is displayed at a particular field and the Reset button rearranges the screen to make it ready for further translations.



Figure 1
Figure 1



Available mobile platforms have several disadvantages that should be taken into account carefully. Extra server or product installation requirement or application signing procedure complexity are examples of these obstacles. I think Android, as a Java developer friendly environment, is pretty enjoyable and a simple mobile application development platform. First of all, it is based on Java and XML technologies similar to trendy and effective platforms. It supports resource bundle usage by also supporting internationalization. Screen development consists of just designning an XML resource with binding a Java bean. Such resources created during demo application are given below.


XML SOURCE CODE ::
<code lang="xml">
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout
android:id="@+id/varTitle1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/welcomeToSample1"
/>


<TextView
android:id="@+id/varInputText_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/inputText"
android:layout_x="40px"
android:layout_y="32px"
>
</TextView>
<EditText
android:id="@+id/varInputText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:layout_x="200px"
android:layout_y="32px"
>
</EditText>


<TextView
android:id="@+id/varSLang_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sourceLang"
android:layout_x="40px"
android:layout_y="82px"
>
</TextView>
<EditText
android:id="@+id/varSLang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:layout_x="200px"
android:layout_y="82px"
>
</EditText>


<TextView
android:id="@+id/varTLang_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/targetLang"
android:layout_x="40px"
android:layout_y="132px"
>
</TextView>
<EditText
android:id="@+id/varTLang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:layout_x="200px"
android:layout_y="132px"
>
</EditText>


<Button
android:id="@+id/btnTranslate"
android:layout_width="87px"
android:layout_height="wrap_content"
android:text="@string/button1"
android:layout_x="40px"
android:layout_y="282px"
>
</Button>

<TextView
android:id="@+id/varResult_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/resultTrans"
android:layout_x="40px"
android:layout_y="332px"
>
</TextView>
<TextView
android:id="@+id/varResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:layout_x="200px"
android:layout_y="332px"
>
</TextView>
<Button
android:id="@+id/btnReset"
android:layout_width="87px"
android:layout_height="wrap_content"
android:text="@string/button2"
android:layout_x="40px"
android:layout_y="382px"
>
</Button>
</AbsoluteLayout>



JAVA BEAN SOURCE CODE ::

package com.example.android.helloactivity;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.AndroidHttpTransport;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class HelloActivity extends Activity {
private EditText inputText;
private EditText sourceLang;
private EditText targetLang;
private TextView resultText;
private Button translateButton;
private Button resetButton;

private static final String SOAP_ACTION = "execute";
private static final String METHOD_NAME = "translationSource";
private static final String NAMESPACE = "http://xmlns.oracle.com/singleString";
private static final String WSURL = "http://192.168.2.4:8001/soa-infra/services/default/TranslationServiceProject/TranslatorMediator_ep?WSDL";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hello_activity);
initControls();
}

private void initControls() {
inputText = (EditText) findViewById(R.id.varInputText);
sourceLang = (EditText) findViewById(R.id.varSLang);
targetLang = (EditText) findViewById(R.id.varTLang);
resultText = (TextView) findViewById(R.id.varResult);
translateButton = (Button) findViewById(R.id.btnTranslate);
translateButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
translate();
}
});
resetButton = (Button) findViewById(R.id.btnReset);
resetButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
reset();
}
});
}

private void translate() {
resultText.setText("error occured");

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

PropertyInfo pi1 = new PropertyInfo();
pi1.setNamespace(NAMESPACE);
pi1.setName("input");
pi1.setType(String.class);
pi1.setValue(inputText.getText().toString());
request.addProperty(pi1);

PropertyInfo pi2 = new PropertyInfo();
pi2.setNamespace(NAMESPACE);
pi2.setName("sourceLanguage");
pi2.setType(String.class);
pi2.setValue(sourceLang.getText().toString());
request.addProperty(pi2);

PropertyInfo pi3 = new PropertyInfo();
pi3.setNamespace(NAMESPACE);
pi3.setName("targetLanguage");
pi3.setType(String.class);
pi3.setValue(targetLang.getText().toString());
request.addProperty(pi3);

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(
WSURL);
try {
androidHttpTransport.call(SOAP_ACTION, envelope);

// Get the SAOP Envelope back and the extract the body
SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;
if(resultsRequestSOAP != null && resultsRequestSOAP.getProperty("output") != null)
resultText.setText(resultsRequestSOAP.getProperty("output").toString());


} catch (Exception E) {
System.out.print("ERROR:" + E.getClass().getName() + ": "
+ E.getMessage());
}
}

private void reset() {
initControls();
}
}



When analyzing the source code, you will see usage of kSOAP framework that helps on calling a web service via Java mobile platform. At that point, usage of such a memory consuming framework in mobile appliation can be discussed. But, I only aimed to create a client of a SOA composite application, thats scenario and details are mentioned before. While researching the topic, I came across with kSOAP and it seemed worth to try. The main problem with the framework was namespace conflict, although the target namespace value was given to the root node, it was not assigned to the given parameters. This caused namespace conflict at the service side. As given at the source code, I needed to assign the same namespace value to each parameter manually. Finally, I am able to say that the combination of these technologies worked well. Figure 2 shows the result of Android application that with respect of given input values, the translation result was displayed at Result field. As analyzing effects at Oracle SOA Suite 11gR1 product side, Figure 3 shows the log output of composite application provided by the callout class.


Figure 2
Figure 2


Figure 3
Figure 3




MEDIATOR'S JAVA CALLOUT SOURCE CODE ::

package com.eteration.sample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

import java.util.Iterator;

import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import oracle.tip.mediator.common.api.AbstractJavaCalloutImpl;
import oracle.tip.mediator.common.api.CalloutMediatorMessage;
import oracle.tip.mediator.common.api.MediatorCalloutException;
import oracle.tip.mediator.utils.XmlUtils;

import org.w3c.dom.Node;

import oracle.xml.jaxp.JXDocumentBuilder;
import oracle.xml.jaxp.JXDocumentBuilderFactory;
import oracle.xml.parser.v2.NSResolver;
import oracle.xml.parser.v2.XMLDocument;
import oracle.xml.parser.v2.XMLElement;
import oracle.xml.parser.v2.XMLNode;

import oracle.xml.parser.v2.XMLText;

import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

public class TranslatorMediatorCalloutClass extends AbstractJavaCalloutImpl {
private static String googleTranslationService =
"http://ajax.googleapis.com/ajax/services/language/translate";

@Override
public boolean postRouting(CalloutMediatorMessage calloutMediatorMessage,
CalloutMediatorMessage calloutMediatorMessage2,
Throwable throwable) throws MediatorCalloutException {
boolean returnValue =
super.postRouting(calloutMediatorMessage, calloutMediatorMessage2,
throwable);
String sPayload = "null";
for (Iterator msgIt1 =
calloutMediatorMessage.getPayload().entrySet().iterator();
msgIt1.hasNext(); ) {
System.out.println("Google Translator postRouting4");
Map.Entry msgEntry = (Map.Entry)msgIt1.next();
Object msgKey = msgEntry.getKey();
Object msgValue = msgEntry.getValue();
sPayload = XmlUtils.convertDomNodeToString((Node)msgValue);
try {
XMLDocument changedoc = XmlUtils.getXmlDocument(sPayload);
XMLNode inputS1 =
(XMLNode)changedoc.selectSingleNode("//inp1:input",
new LocalNamespaceResolver());
System.out.println("the value of the source text = " +
inputS1.getTextContent());
XMLNode inputS2 =
(XMLNode)changedoc.selectSingleNode("//inp1:sourceLanguage",
new LocalNamespaceResolver());
System.out.println("the value of the sourceLanguage = " +
inputS2.getTextContent());
XMLNode inputS3 =
(XMLNode)changedoc.selectSingleNode("//inp1:targetLanguage",
new LocalNamespaceResolver());
System.out.println("the value of the targetLanguage = " +
inputS3.getTextContent());

XMLDocument doc =
prepareReturnMessage(inputS1.getTextContent(),
inputS2.getTextContent(),
inputS3.getTextContent());
if (doc != null) {
String mykey = "reply";
calloutMediatorMessage2.addPayload(mykey,
doc.getDocumentElement());
}

} catch (Exception e) {
System.out.println(e);
}
} //for
return returnValue;
}

private XMLDocument prepareReturnMessage(String input,
String sourceLanguage,
String targetLanguage) throws ParserConfigurationException {
JXDocumentBuilderFactory factory =
(JXDocumentBuilderFactory)JXDocumentBuilderFactory.newInstance();
JXDocumentBuilder documentBuilder =
(JXDocumentBuilder)factory.newDocumentBuilder();
XMLDocument doc = (XMLDocument)documentBuilder.newDocument();
doc.setVersion("1.0");
doc.setEncoding("UTF-8");
XMLElement rootElement =
(XMLElement)(doc.createElementNS("http://xmlns.oracle.com/singleString",
"translationResult"));
doc.appendChild(rootElement);
XMLElement inputElement = (XMLElement)(doc.createElement("output"));
rootElement.appendChild(inputElement);
String translation = this.translate(input, sourceLanguage, targetLanguage);
System.out.println("translation result = " + translation);

if (translation != null && translation.equalsIgnoreCase(input))
return null;

XMLText translationElement = (XMLText)doc.createTextNode(translation);
inputElement.appendChild(translationElement);
return doc;
}

class LocalNamespaceResolver implements NSResolver {
public String resolveNamespacePrefix(String prefix) {
return "http://xmlns.oracle.com/singleString";
}
}

private static String extractTranslationFromJSON(String response) {
final JSONObject jsonObj = (JSONObject)JSONValue.parse(response);
String translation = null;
if (jsonObj != null && jsonObj.containsKey("responseData")) {
final JSONObject responseData =
(JSONObject)jsonObj.get("responseData");
translation = responseData.get("translatedText").toString();
}
return translation;
}

public static String translate(String sourceString, String sourceLanguage,
String targetLanguage) {
return extractTranslationFromJSON(translateString(sourceString,
sourceLanguage,
targetLanguage));
}

private static String translateString(String sourceString,
String sourceLanguage,
String targetLanguage) {
HttpURLConnection connection = null;
OutputStreamWriter wr = null;
BufferedReader rd = null;
StringBuilder sb = null;
String line = null;

URL serverAddress = null;

try {
serverAddress =
new URL(googleTranslationService + "?v=1.0&&q=" + sourceString.replace(' ','+') + "&&langpair=" + sourceLanguage + "%7C" + targetLanguage);
connection = null;
connection = (HttpURLConnection)serverAddress.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setReadTimeout(10000);
connection.connect();
rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
sb = new StringBuilder();

while ((line = rd.readLine()) != null) {
sb.append(line + '\n');
}

return (sb.toString());

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
connection.disconnect();
rd = null;
sb = null;
wr = null;
connection = null;
}
return null;
}
}

Monday, 8 March 2010

Custom ToolTip on NavBar and TabBar components

In Flex, when you want to give a tool tip text for visual component that extends UIComponent class, set the value of toolTip property with the desired text.
However, it is possible to create custom ToolTips for your visual components by implementing mx.core.IToolTip interface in your custom component. After creating a custom component, you should add a handler to override the basic toolTip mechanism of the target component by intercepting toolTipCreate event.

You can find lots of samples about customization of toolTips in the blogs and adobe's website http://livedocs.adobe.com/flex/3/html/help.html?content=tooltips_4.html .

Here, I wanted to show how to customize toolTips on NavBar and TabBar subclasses (such as ButtonBar, LinkBar, and ToggleButtonBar) support ToolTips in their data providers.

Firstly, I showed how to assign toolTips for the children in BasicToolTipButtonBar.mxml component. Here, toolTipField property of ButtonBar is used to specify which field of dataProvider array will be displayed as tooltip.

<?xml version="1.0" encoding="utf-8"?>
<mx:ToggleButtonBar xmlns:mx="http://www.adobe.com/2006/mxml"
labelField="name"
toolTipField="code" dataProvider="{courseList}">

<mx:Script>
<![CDATA[
[Bindable]
private var courseList:Array = [{name:'C Programming', code:'C140'},
{name:'PL Concepts', code:'C242'}, {name:'Software Engineering', code:'C350'}];
]]>
</mx:Script>
</mx:ToggleButtonBar>

After this basic sample, I took a step forward to customize the displayed toolTip in CustomToolTipButtonBar.mxml component. I used a Panel container as custom component to display course info on it. To achive this, you should implement a tricky solution by intercepting the children components' creations in the navigation bar and adding ToolTipEvent.TOOL_TIP_CREATE event listener for all of them. The rest is the same when you customize a toolTip.

<?xml version="1.0" encoding="utf-8"?>
<mx:ToggleButtonBar xmlns:mx="http://www.adobe.com/2006/mxml"
labelField="name"
toolTipField="code" dataProvider="{courseList}"
updateComplete="updateCompleteListener(event)">

<mx:Script>
<![CDATA[
import mx.controls.Button;
import mx.events.FlexEvent;
import mx.events.ToolTipEvent;
[Bindable]
private var courseList:Array = [{name:'C Programming', code:'C140'},
{name:'PL Concepts', code:'C242'}, {name:'Software Engineering', code:'C350'}];

private function updateCompleteListener(event:FlexEvent):void {
if (this.getChildren() == null) {
return;
}
for each (var btn:Button in this.getChildren()) {
btn.addEventListener(ToolTipEvent.TOOL_TIP_CREATE, onCreateToolTip);
}
}

private function onCreateToolTip(e:ToolTipEvent):void {
var btnLbl:String = Button(e.target).label;
var toolTipLbl:String = Button(e.target).toolTip;

var customToolTip:ToolTipComponent = new ToolTipComponent();
customToolTip.title = "Course Code: " + toolTipLbl;
customToolTip.courseName = btnLbl;
e.toolTip = customToolTip;
}
]]>
</mx:Script>
</mx:ToggleButtonBar>


Java Developer Diaries; Developing Android Applications

On September 6th, 2007 i received a message from Chloe Arrowsmith of Google over Linkedin, asking if I am interested in a position Mobile Applications software engineering team they are building in London. As you may guess this team was setup for building Android and they didn't hire me in the end :).

Since then I am trying watch android closer. Frankly there things I like in android and there are things i don't.

Android is a mature platform thanks to google's strategy to release the sdk to public much before than any device available. When I start to deal with android i realized I am comparing every structure with iPhone and objective-c which is actually weird because I am a Java guy more than Objective-C. Like it or not iPhone and Objective-C is a well organized and elegant platform to work on and the deeper I dive into android sdk, the more I find things sometimes not so easy and well organized.

Honestly I am not really interested in JavaME since beginning since I find it a bit limited but new coming devices and SDK (such as Android and IPhone) are much more sophisticated and capable. Android offers much more than IPhone SDK can even imagine. You can code Activities which are the building blocks of user interfaces. You can use content providers to access and share data between applications. Besides you can use Intents to get noticed about various events, from hardware state changes to incoming data, to application events and also not only can you respond to intents, but you can create your own, to launch other activities, or to let you know when specific situations arise which you can't on an IPhone. There is one other key stuff which IPhone lacks, the services which can keep running even not related to an activity, like keep listening messages even if you close the control unit of your instant messaging client.

These were the best and most promising part since most of them are only available on Android devices. However I find the UI and controller integration a bit troublesome. Also even if the UI controller structures seems like taken from Objective-C, they don't seem as neat.

Enough talking lets see things in action;

If you had read my previous post on developing IPhone application, why don't we just build the same on Android, which will use GPS, accelerometer and UI actions (if not you can go back to check the iphone post since it may lead you a better comparison, which is, however, not necessary). First of all I assume you downloaded and setup the Android SDK and ADT Eclipse Plugin. The installation is pretty straight forward and ran smoothly on mac and ubuntu (should be ok on windows too). I also assume you have basic knowledge of eclipse and java development on eclipse.

Fire up your eclipse and create a new android project, as if you are creating a java project.



Next type a project, application and package name. We also need to specify a target runtime which I choose 2.1. Since we are not using any new apis it should be ok to select as low as 1.5. Click finish to create your project.



You may have noticed some errors in your project which is actually not a real problem.



If you clean and rebuild you project the errors will be gone. This seems like a small issue in ADT plugin which should be either because of not running the incremental builders in project creation time or not cleaning the error markers after the first build, whichever it is, just nevermind.



The MainActivity class is created with an overridden onCreate method which is fired when the activity is first created. Android has a different way of UI declaration. Here the main.xml file under layout folder is used for creating the UI layout which also provides a visual designer. strings.xml under values folder is used to hold static values. We would be able to change those within out code. To be honest I really like this approach, it is quite easy, well organized and the visual designer is a great plus. Also if you are coming from a xml declarative platform such as Flex(MXML) or Silverlight(XAML) you won't find it much different (which actually is).



Even at this stage you might realized Android application has much less files than an iPhone application (can check previous post). Although these makes it appear simpler and easier to start with, the deeper you go you realized Objective-C is a bit more organized. Open MainActivity class which acts as the view controller. The basic usage of the APIs would not be very different than iPhone, we are going to implement a listener interface, register or class as the listener and code the implementation method.

Lets start with building our interface, the default view already has a TextView printing hello. We can modify this one and add another to display our latitude and longitude.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/latitude"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/longitude"
/>
</LinearLayout>


You may also noticed ‘id’ attributes are added in order to access this components within the code. As I mentioned before this approach is much like other XML declerative platforms. By the way if you feel comfortable (or brave enough) you may also try tweak the UI using the layout view.



Since this should be enough for the view lets go back to our activity class. The MainActivity class is created with an overridden onCreate method which is fired when the activity is first created.

First lets create two TextViews to control our UI code and get the LocationManager to access the GPS.


public class MainActivity extends Activity {

private LocationManager locationManager;
private TextView latitude;
private TextView longitude;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//bind the ui components to code referances
latitude = (TextView) findViewById(R.id.latitude);
longitude = (TextView) findViewById(R.id.longitude);
//get the locationManager
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
//...


So far the most suprising thing for me was the need to bind the UI components to code references manually via findViewById method. Honestly this seems a bit unnecessary and weird. I was expecting the compiler to access UI components dynamically (as in other xml declarative languages) or use visual tools to do the job (as in interface builder on mac). This seems fine for now but more complicated views might become troublesome.
Since we are mostly done with the UI code we can start utilizing the GPS. We already added and initiated the location manager.

This would be enough get the location manager but to get the location updates we need to register a listener. To keep things simple and more like what I did in the iPhone tutorial, I am going to implement the needed listener interfaces to our activity class. You may prefer to create anonymous listener classes.


public class MainActivity extends Activity implements LocationListener {


Next we create two methods to register our class as the listener of the location updates via using locationManager.requestLocationUpdates method. This method provider constant, minimum time interval, minimum distance interval and finally the listener class.


private void startListening() {
//registers our class as the listener
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
0, this);
}

private void stopListening() {
locationManager.removeUpdates(this);
}


Since the methods are ready we can call startListening in onCreate method to register our class as the listener of location updates.


...
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
startListening();
...


Implementing the LocationListener interface brings four new methods to be implemented. To avoid errors lets create those and also implement the onLocationChanged method.


public void onLocationChanged(Location location) {
latitude.setText(location.getLatitude()+"");
longitude.setText(location.getLongitude()+"");
stopListening();
}

public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub

}

public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub

}

public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub

}


Any new location update will trigger onLocationChanged method. However we don’t need any update after we get the locations so as we get location update we assign those to UI text fields and call stopListening to unregister our listener class.

As you may remember from the iPhone post we want our application to update the location info when we shake the handheld. To achieve this we need to ask the sensor service to inform us on accelerometer events. This approach is a bit primitive when compared to shake API introduced in iPhone OS 3. However it is much or same with the older iPhone OS. First lets get the sensor manager.


private SensorManager sensorManager;


And in onCreate method initialize the sensorManager and add a listener.


...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensorManager.registerListener(this, sensorManager.getSensorList(
Sensor.TYPE_ACCELEROMETER).get(0), 100);
...


We also need to implement a new interface to let our class to become a listener for SensorEvents.


public class MainActivity extends Activity implements LocationListener, SensorEventListener {


Adding the interface will cause errors because of unimplemented methods. Add the needed methods and implement the onSensorChanged method to detect shake and reregister for GPS updates.


// The threshold value to detect shake
private float kThreshold = 1.2f;
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float[] values = event.values;
if (values[SensorManager.DATA_X] > kThreshold
|| values[SensorManager.DATA_Y] > kThreshold
|| values[SensorManager.DATA_Z] > kThreshold) {
startListening();
}
}
}


Finally we want our UI to respond and rotate according to orientation changes. Unlike the iPhone counterpart, android does not need any code change for this purpose, just tweak the AndroidManifest.xml and it is done!





Although ADT offers visual editors for this xml file, it is not possible to change the screenOrientation parameter visually.



Now we are ready to run our application. Android SDK comes with an emulator. To set up new virtual devices, use awd manager.



You can add virtual devices varying from version 1.1 to 2.1. The SDK comes with 2.1 version but other packages can also be downloaded from available packages section.



Be careful about not choosing an older AVD version than the project build target you choose, shown in figure 2. As our AVD is ready now we can run the application. Right click on the project and select run as android application.



This should fire the emulator and deploy your project which should get an error as shown below.



Unlike iPhone, Android offers much more services and integration to developers which brings up another problem, the security. Android programming model expects you to declare the resources you want to use at the time of installation, so instead of asking permission each time the application started, Android lets the user know what the application doing during installation. While this approach is much simpler and less pain for the user, it will also provide eternal access to resources once user confirms.

To add those permissions open the AndroidManifest.xml and go to permissions tab.



Click add.



And add ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION permissions from the dropdown.



Finally our application is really ready to run. I had some difficulties getting location data on the emulator. Also shaking the emulator window didn’t cause the accelerometer to detect any shake. However when I deployed the application on a real device everything ran smoothly. Later i realized I need to install SensorSimulatorSettings.apk to get mock location and trigger shake. To install use the following command;

%ANDROID_SDK_HOME%/tools/adb install SensorSimulatorSettings.apk

You can also refer this post for more info about SensorSimulatorSettings.

The running application should be similar to the screenshot below, responding to shake and orientation changes. (BTW thanks to Google giving the developer phone last year at I/O).



Android is a very promising platform and although its quite young its already quite mature. I will later write another post comparing iPhone and Android development but to tell the truth staying in Java and having a more open and flexible platform feels more comfortable. However when compared to iPhone documentation, samples and even books are still might not be as good.