Introduction
As the last piece of the 3-piece architecture is implementation of the Android application which will be able to register and receive notification messages from GCM.
The complete Android application can be downloaded from here.
The sending of the notification is done in following order:
1. Google App engine – submit a message | 2. Android application receives a notification | 3. Android notification tray preview |
![]() | ![]() | ![]() |
Implementation
The first part of Android application would be the communication to backend server that we developed before by using Google App Engine. This communication is done in asynchronous way and for this reason AsyncTask class has been extended. GAEClient is in charge of handling HTTP requests. There is only single method implementation (storeRegistrationId) that is called once the device token is received and needs to be stored on the server.
public class GAEClient extends AsyncTask<Object, Void, String> {
// TODO: Change URL to Google App Engine application URL
private static final String URL = "http://<APP_NAME>.appspot.com/";
private static final String POST_ID_PARAM = "txtRegId";
private static final String POST_MSG_PARAM = "txtInput";
private String res;
@Override
// Checks HTTP page requests
protected String doInBackground(Object... objects) {
String action = (String)objects[0];
if(action.contains("storeid"))
{
String param = (String) objects[1];
return storeRegistrationId(param);
}else{
return null;
}
}
// Stores device token on the backend server
public String storeRegistrationId(String id){
String result = null;
try{
DefaultHttpClient client = new DefaultHttpClient();
HttpPost request = new HttpPost(URL+"storeid");
request.setHeader("Content-type", "application/x-www-form-urlencoded");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair(POST_ID_PARAM, id));
request.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(request);
result = String.valueOf(response.getStatusLine().getStatusCode());
return result;
}catch(Exception e){
e.printStackTrace();
return "400";
}
}
@Override
protected void onPostExecute(String result) {
res = result;
}
}
The second part is GCMIntentService. This class is in charge of receiving a notification from the GCM and dispatching its message via broadcast to all Activities that will receive this message if they have broadcast listener implemented. In this simple demo, with single activity, only MainActivity will receive a message.
public class GCMIntentService extends GCMBaseIntentService {
@Override
protected void onMessage(Context context, Intent intent) {
String message = intent.getStringExtra("message");
if(message!=null){
Intent i = new Intent();
i.setAction("GCM_RECEIVED_ACTION");
i.putExtra("gcm", message);
context.sendBroadcast(i);
}
}
@Override
protected boolean onRecoverableError(Context context, String errorId) {
return super.onRecoverableError(context, errorId); //To change body of overridden methods use File | Settings | File Templates.
}
@Override
protected void onError(Context context, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
protected void onRegistered(Context context, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
protected void onUnregistered(Context context, String s) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
Once the Activity receives a message, the following step is to preview a message. They are few ways to display a notification, but the most common way is to use notification drawer (i.e. notification tray). NotificationDrawerMng builds notification for notification drawer preview.
public class NotificationDrawerMng{
public static Notification createNotification(Context context, String title, String message) {
// Prepare intent for notification display in
// the notification tray
Intent intent = new Intent();
intent.putExtra("message",message);
intent.putExtra("title",title);
int requestID = (int) System.currentTimeMillis();
PendingIntent pIntent = PendingIntent.getActivity(context, requestID, intent, 0);
// Build notification for tray display
Notification notification = new Notification.Builder(context)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pIntent)
.build();
return notification;
}
}
In the broadcast listener, in the MainActivity, notification will be actually set inside the notification tray.
BroadcastReceiver gcmReceiver = new BroadcastReceiver() {
// Broadcast listener that receives a dispatched notification previously received
// from GCMIntentService
@Override
public void onReceive(Context context, Intent intent) {
broadcastMessage = intent.getExtras().getString("gcm");
if (broadcastMessage != null) {
Toast.makeText(getApplicationContext(), broadcastMessage, Toast.LENGTH_LONG).show();
Notification notification = NotificationDrawerMng.createNotification(getApplicationContext(), "GCMAndroidDemo", broadcastMessage);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notification.flags = notification.flags | Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
}
}
};
The last step is to add additional permissions in AndroidManifest for using GCM. Although we are using GCM don’t get confused since C2DM remained a configuration tag.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gcmdemo.GCMAndroidDemo"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="14"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<permission android:name="com.gcmdemo.GCMAndroidDemo.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.gcmdemo.GCMAndroidDemo.permission.C2D_MESSAGE" />
<!-- App receives GCM messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity android:name="MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.gcmdemo.GCMAndroidDemo" />
</intent-filter>
</receiver>
<service android:name="com.gcmdemo.GCMIntentService" />
</application>
</manifest>