How To Develop Smart Android Notifications using Google ... - SECC

tibburfrogtownMobile - sans fil

14 déc. 2013 (il y a 3 années et 5 mois)

79 vue(s)


Software Engineering


Competence Center



TUTORIAL




© Copyright Software Engineering Competence Center 2013













How To
Develop Smart Android Notifications
u
sing Google Cloud Messaging Service




Ahmed Mohamed Gamaleldin

Senior
R&D Engineer
-
SECC

ahmed.gamal.eldin@itida.gov.eg














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
2


Abstract


Google Cloud Messaging for Android (GCM) is a service that helps developers
to
send data from servers to their Android applications on Android devices. The
service was unveiled on June 27, 2012, at
Google I/O 2012

held at
the
Moscone
Center

in San Francisco

[1]
.

The GCM service handles all aspects of
queuing

of
messages and delivery to the target Android application running on the target
device.
It

is completely free whatever
your messaging needs are

and it
can be
used in some applications like
smart notification system
s
.


This tutorial
gives an overview about

the
Google GCM
service
and provides
hands
-
on experience

on using

this technology in
a ca
se study for

energy
-
aware
smart home application developed
at

Software
Engineering

Competence Center
(
SECC
)
.


Keywords:

Google Cloud Messaging (GCM)
,
Cloud to Device Messaging (C2DM)
,
Android smart notifications
.

















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
3


T
able of Contents


1.

Introduction

4

2.

Getting started with the GCM service

4

3.

How the GCM works?

10

3.1.

GCM Lifecycle

12

4.

Example of Android Application that Uses the GCM

12

5.

Architecture of Android Application that uses GCM

14

5.1.

GCM process flow

14

5.1.1.

Enabling GCM

15

5.1.2.

Sending a message

15

5.1.3.

R
eceiving a message

16

5.2.

Application server App

16

5.3

Android App

18

5.3.1

Creating the Manifest file

19

5.3.2

Android app structure

22

6.

Invoker Application

34

6.1.

Invoker example architecture

35

7.

Summary

37

8.

References

38

9.

Abbreviations

38

















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
4


1
.

Introduction


Google Cloud Messaging for Android (GCM) is a service that allows you to send
data from your server to
the

users' Android
-
powered device. This could be a
lightweight message telling your app there is new data to be fetched from the
server

like new version
of apps or something like that

[1]
.


The GCM service handles all aspects of
storing, queuing
and delivery

of messages

to the target Android application running on the target device.
It
is
a
completely
free

service
whatever

your messaging needs are.


Google Cloud Messaging technology is the new
version of

the C2DM (cloud to
device messaging) technology

as the
C2DM
service
has been officially
deprecated
as of June 26, 2012 which
means that C2DM has stopped accepting new users
and quota requests
.

The GCM

could be considered as a more efficient
implementation of the C2DM technology.


The GCM service
has

many characteristics

as described in
[
2
]
:


1
.

It allows 3rd
-
party application servers to send messages to their Android
applications.

This is a key feature as you always need your
server
application to be in direct contact with
the mobile application

such that
you can send messages to the
mobile
application about new versions for
instance.

2
.

An Android application on an Android device doe
sn't need to be running
to receive messages. The system will wake

it

up the Android application
via Intent broadcast when the message

arrives. This is achieved if
the
application is set up with the proper bro
adcast receiver and permissions
in the AndroidMa
nifest.xml file.

3
.

The application

has full control of how to handle
the GCM messages
passed to it
. For example, the application might post a notification

when
receiving these messages
.

4
.

It requires devices running Android 2.2 or higher that also have the
Google Play Store application installed
.


2
.

Getting
started

with the GCM service


T
o
start writing

an Android application and the server
-
side
application
using the
client and server
helper libraries

provided by GCM, you must
begin with

the first












How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
5


step which is creating a Google API project.

The following steps explain how the
Google API proje
ct is created

[
1
]
:


1
.

Open the Google API console page

https://code.google.com/apis/console/


2
.

If you haven't created an API project yet, this page will
ask

you to do so
:




3
.

If you already have existing projects, the first page you see will be the
Dashboard

page. From there you can create a new project by opening the
project drop
-
down menu (upper left corner) and choosing
Other
projects > Create
.














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
6



4
.

After

creating
the
project. Your browser URL will change to something
like
:
https://code.google.com/apis/console/#project:514132917049


You’ll need to keep
the value after #project: (51413291704
9 in this
example). This is your project number, and it will be used later on as the
GCM sender ID.


5
.

It is required now to enable the GCM service through the following steps:

a
.

In the main Google APIs Console page, select
Services
.


b
.

Turn the
Google Cloud
Messaging

toggle to ON.













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
7



c
.

In the Terms of Service page, accept the terms.


6
.

After enabling the service, the API key is required. To obtain it:

In the main Google APIs Console page, select
API Access
. You will see a
screen as like
:


















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
8



7
.

Click
Create
new Server key
.
Note that e
ither a server key or a browser
key should work. The advantage
of

using a server key is that it
gives you
more control on

the
IP addresses

that can access your app (this feature is
not used in our application below)
. The followin
g screen appears
,
just
click the Create button
:


8
.

Take note with the API key that is shown after that:
















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
9



9
.

Up to this step, you have finished creation of the Google API proejct and
toke a note with

the project number and the API key. For development,
you’ll need to install the helper libraries from the SDK manager as follow:




From the SDK Manager, install
Extras > Google Cloud Messaging for




Android Library
. This creates a
gcm

directory under






YOUR_SDK_ROOT
/extras/google/

containing these subdirectories:
gcm
-




client
,
gcm
-
server
,
samples/gcm
-
demo
-
client
,
samples/gcm
-
demo
-
server
, and




samples/gcm
-
demo
-
appengine

















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
10



3
.

How the GCM works
?


There are some

key terms and concepts involved in

the

GCM

service and it is
very important to have a good knowledge about them. The key terms and
concepts of the GCM are divided into two categories

[
2
]
:



Components



The physical
items

involved

in GCM

steps
.



Credentials



The IDs
that are used in different stages of GCM to
achieve
the authentication,

and
to be sure that
the message is going to the correct
application and the correct Android device
.




Table 1 below explains the
previous
GCM concepts

with clear examples














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
11


Table
1

GCM concepts


Components



Mobile Devices



The device that is running an Android application that uses
GCM



3rd
-
party Application Server



The 3rd
-
party application server sends data to an Android
application on the
device via the GCM server.



GCM Servers



The Google servers
used

in taking messages from the 3rd
-
party application server and sending them to the device.





Credentials



Sender ID


A project number y
ou acquire from the API console
.

The sender ID is
used in the
registration process

to identify an Android application that
is permitted to send messages to the device



Application ID


The Android application that is registering to receive messages. The
Android application is identified by the package name from the
manifest
.xml file
. This ensures that the messag
es are targeted to the
correct Android application



Registration ID


An ID issued by the GCM servers to the Android application that allows
it to receive messages. Once the Android application has the
registration ID, it sends it to the 3rd
-
party applica
tion server, which
uses it to identify each device that has registered to receive messages
for a given Android application. In other words, a registration ID is tied
to a particular Android application running on a particular device.














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
12



Google User Account



For GCM to work, the mobile device must include at least one Google
account if the device is running a version lower than Android 4.0.4.


Sender Auth Token



An API key that is saved on the 3rd
-
party application server that gives
the application server

authorized access to Google services. The API
key is included in the header of POST requests that send messages.



3
.
1
.


GCM Lifecycle


The
usage of the
GCM process
requires the following

phases:


1
.

Enabling GCM

-

An Android application running on a mobile device
registers

itself

to
be able to
receive messages.

2
.

Sending a message

-

A 3rd
-
party application server sends messages to
the device.

3
.

Receiving a message

-

An Android application receives a message from a
GCM server.


4
.

Example of
Android A
pplication
that
U
ses the GCM


This section will explain an Android application
used in the energy
-
aware smart
home project developed by SECC.

This app was

based on the GCM demo

application provided by Google

[3]
.

We’
ll cover the details of that

application
with
all of the

code snapshots

in the next section


The android application architecture is described in
Error! Reference source not
ound.
. It consists of three parts:


1
.

Application server App

(Here called GCM server)

2
.

GCM client App (the Android App)

3
.

GCM
cloud
service


The following is an explanation for the scenario shown in
Error! Reference
ource not found.


1
.

At the device start up, the installed Android app (GCM c
lient) sends a
registration request to the GCM server asking for a registration id. This
registration request uses the Google API project ID to identify the
Android device that asks for the registration id.













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
13


2
.

The GCM server responds to the previous request a
nd sends the
registration id to the Android
device
.

The

Android app sends this
registration

id to server application which
stores it in its internal storage
.



Figure
1

GCM application example in smart home building application


3
.

The fault detector KP is subscribed for smart home devices faults. When it
detects any fault, it invokes the server application

4
.

The server application sends a message to the Android device, where it
sends a request to the GCM server via its helper classes
APIs including the
Google API project ID and the server API key.

5
.

When the GCM server finds the Android device online, it’ll pass the
message to it through a broadcast intent. The broadcast receiver
GCMIntentService intent in the Android device is responsib
le for
receiving this broadcast message and invoking the notification

manager












How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
14


to create a new notification.


First, we need to state the list of tools required to develop
this

App. Table 1
shows these tools




Tool

Eclipse Indigo or Eclipse Juno

Android ADT plugin

Apache Tomcat Application server v7.1or later

Apache
Ant 1.8

or later


For the web server:



Ant 1.8
, it is a project building tool and it is used for building
the server
-
side application as a .war file



A running web server compatible with Servlets API version 2.5, such as
Tomcat 7



Google account registered to use GCM.



The API key for that account.


For the Android applicat
ion:



Eclipse with the ADT plugin



Emulator (or device) running Android 2.3 (Ginger
-
bread) or higher with
Google APIs.



The Google API project number of the account registered to use GCM
.

5
.

Architecture of Android Application that uses GCM


In this section,
we’ll cover in details the architecture of the Android app
that uses the GCM service and also we’ll cover the 3d party application
server app.


5
.
1
.

GCM process flow






As mentioned above the GCM service has three main steps:




Enabling GCM




Sending a message




Receiving a message














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
15


5
.
1
.
1
.

Enabling GCM


This is the sequence of events that occurs when an Android application
running on a mobile device registers
itself into the GCM server
to receiv
e
messages:


1
.

The first time the Android application needs to use the messaging
service, it
sends

registration

i
ntent to a GCM server.

This registration Intent (
com.google.android.c2dm.intent.REGISTER
)
includes the sender ID, and the Android application ID
.


2
.

If the registration is successful, the GCM server broadcasts a
com.google.android.c2dm.intent.REGISTRATION

intent which gives the
Android application a registration ID.

The Android application should store this ID for later use (for
instance, to check on
onCreate()

if it is already registered).


3
.

To complete the registration, the Android application sends the
registration ID to the application server. The application server stores
the registration ID in a database.


5
.
1
.
2
.

Sending
a

m
essage


For an application server to send a message to an Android appli
cation,
the following things must be in place:




The Android application has a registration ID that allows it to
receive messages for a particular device.



The 3rd
-
party application server has stored the registration ID.



An API key.
It is a key for the application on the application server
and it is previously set up in the api.key file that exists in the
application server app that will be explained later
.



Here is the sequence of events that occurs when the application server
send
s a message:

1
.

The application server sends a message to GCM servers.

2
.

GCM servers
store the message in case the device is offline.

3
.

When the device is online, Google sends the message to the device.













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
16


5
.
1
.
3
.

Receiving a message

This is the sequence of eve
nts that occurs when an Android
application installed on a mobile device receives a message:


1
.

The system receives the incoming message and extracts
any data

from
it,

if any.

2
.

The system passes the key/value pairs to the targeted Android
application in a
com.google.android.c2dm.intent.RECEIVE

Intent as a
set of extras.

3
.

The Android application

processes the message

5
.
2
.

Application server App



The application server
used here is the Apache Tomcat v7.0
which is a servlet

container that can accept HTTP requests and send HTTP commands to the
GCM server
. We don’t need to develop a new application server where the
GCM Demo
server
application
provided by Google
can be used directly. The
following steps explain how to use it:


1
.

From the SDK Manager, install Extras > Google Cloud Messaging for
Android Library.

2
.

This creates a gcm directory under YOUR_SDK_ROOT/extras/google/
containing these subdirectories: gcm
-
client, gcm
-
server, samples/gcm
-
demo
-
client, samples/gcm
-
demo
-
server, a
nd samples/gcm
-
demo
-
appengine.

3
.

You can create a web application from Eclipse and copy the gcm
-
demo
-
server app into it as shown below

4
.

In a text editor

or from inside E
clipse
, edit the samples/gcm
-
demo
-
server/WebContent/WEB
-
INF/classes/api.key

and replace the existing
text
(if any)
with the API key obtained above.















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
17


$ ant war


Buildfile:build.xml


init:




[mkdir] Created
dir: build/classes




[mkdir] Created dir: dist


compile:




[javac] Compiling 6 source files to build/classes


war:






[war] Building war:
dist/gcm
-
demo.war


BUILD SUCCESSFUL

Total time: 0 seconds




5
.

In a shell window, go to the
samples/gcm
-
demo
-
server

directory.

6
.

Generate the server's WAR file by running
ant war
:














Now the
.
war file is ready to be depl
oyed
in
to

your a
pplication server,

For
instance, if you're using Tomcat

as in our case
, copy gcm
-
demo.war to the
${CATALINA_HOME}/
webapps directory of the Tomcat installation
. Starting
the Tomcat will make this application running waiting for
inquires

that will

be sent

to it from the invoker app that will be explained later.














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
18




For more information about how the 3
rd

part
y

application server works, and
how it sends messages either in text or JSON format, you can refer to
[2]

5
.
3

Android App

To write Android applications that use GCM, you must have an application
server described
above
. This section describes the steps you take to create a
client application that uses GCM.


Our client app is based on the gcm
-
demo
-
client app that exists in
YOUR
_SDK_ROOT/extras/google/
samples


You can follow these steps to use the gcm
-
demo
-
client app:


1
-

Create new Android project in Eclipse with the name gcm
-
demo
-
client

2
-

Copy the package
com.google.android.gcm.demo.app

from
YOUR_SDK_ROOT/extras/google/
samples/gcm
-
demo
-
client and paste it
in the eclipse project

3
-

Add the gcm.jar file into your project’s lib
s
1

directory (this is done by just
copying it into libs folder)

4
-

Open the AndroidManifest.xml from
YOUR_SDK_ROOT/extras/google/
samples/gcm
-
demo
-
client and copy its
contents in the AndroidManifest.xml file in your local eclipse project





You must see now the following project structure:



1

The libs

directory is by default existing in the project class path so if you don’t want to add gcm.jar in
this directory, you’ll just need to add the path of it into your class path













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
19





There are two primary steps involved in writing a client Android application:



Creating a manifest that contains the permissions

the Android
application needs to use GCM.



Implementing your code. To use GCM, this implementation must
include:

o

Code to start and stop the registration service.

o

Receivers for the
com.google.android.c2dm.intent.RECEIVE

and
com.google.android.c2dm.intent.R
EGISTRATION

intents.


5
.
3
.
1

Creating the Manifest

file

Every Android application must h
ave an AndroidManifest.xml file

in its root
directory. The manifest presents essential information about

the Android
application to the
Android system
. To use the GCM feature,

the manifest mu
st
include
the following:



The
com.google.android.c2dm.permission.RECEIVE

permission so the
Android application can register
itself
and receive messages.




The
android.permission.INTERNET

permission so the Android
application can send the reg
istration ID to the 3rd party server.













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
20




The
android.permission.GET_ACCOUNTS

permission as GCM requires a
Google account (necessary only if the device is running a version
lower than Android
ICS
4.0.4)





The

android.permission.WAKE_LOCK

permission so the application
can keep the processor from sleeping when a message is received.




An application

p
ackage + "
.permission.C2D_MESSAGE
permission to
prevent other Android applications from registering and receiving the
Android application's mes
sages. The permission name must exactly
match this pattern

otherwise the Android application will not
receive the messages.

A
receiver for
com.google.android.c2dm.intent.RECEIVE

and
com.google.android.c2dm.intent.REGISTRATION
, with the category set
as
application

p
ackage. The receiver should require the
com.google.android.c2dm.SEND

permission
, to ensure

that only intents
sent by the GCM system framework are sent to the receiver (a regular
application cannot issue intents with that permission).


This bro
adcast receiver is responsible for handling the
above
2 intents
that can be sent by GCM (
com.google.android.c2dm.intent.RECEIVE

and
com.google.android.c2dm.intent.REGISTRATION
)
and it is defined here
in the manifest file
so that these intents can be receiv
ed even if the
application

is not running.




An intent service to handle the intents received by the broadcast
receiver.

This intent service will be called by the
GCMBroadcastReceiver (which is provided by the GCM library
)
. It
could
be a subclass of

com.google.android.gcm.GCMBaseIntentService
,
and it
must contain a public constructor, and should be named
my_app_package.GCMIntentService





S
et android:minSdkVersion
="8" in the manifest. This ensures that the
Android application cannot be installed in an environment in which it
could not run properly.


Here’
s

the AndroidManifest.xml file
of the gcm
-
demo
-
client pr
o
ject

















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
21









































<?
xml

version
=
"1.0"

encoding
=
"utf
-
8"
?>

<
manifest

xmlns:android
=
"http://schemas.android.com/apk/res/android"


package
=
"com.google.android.gcm.demo.app"


android:versionCode
=
"1"


android:versionName
=
"1.0"

>



<
uses
-
sdk

android:minSdkVersion
=
"8"

android:targetSdkVersion
=
"16"
/>



<
uses
-
permission

android:name
=
"android.permission.INTERNET"

/>



<
uses
-
permission

android:name
=
"android.permission.GET_ACCOUNTS"

/>



<
uses
-
permission

android:name
=
"android.permission.WAKE_LOCK"

/>



<
permission


android:name
=
"com.google.and
roid.gcm.demo.app.permission.C2D_MESSAGE"


android:protectionLevel
=
"signature"

/>


<
uses
-
permission


android:name
=
"com.google.android.gcm.demo.app.permission.C2D_MESSAGE"

/>



<!
--

This
app

has permission to register and receive data message.
--
>


<
uses
-
permission


android:name
=
"com.google.android.c2dm.permission.RECEIVE"

/>



<!
--

Main activity.
--
>


<
application


android:icon
=
"@drawable/ic_launcher"


android:label
=
"@string/app_name"

>


<
activity


android:name
=
".DemoActivity"


android:label
=
"@string/app_name"


android:screenOrientation
=
"portrait"

>


<
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
>


<!
--

Receives the actual messages.
--
>


<
action

android:name
=
"com.google.android.c2dm.intent.RECEIVE"

/>


<
!
--

Receives the registration id.
--
>


<
action

android:name
=
"com.google.android.c2dm.intent.REGISTRATION"

/>


<
category

android:name
=
"com.google.android.gcm.demo.app"

/>


</
intent
-
filter
>


</
receiver
>



<
service

android:name
=
".GCMIntentService"

/>


</
application
>


</
manifest
>













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
22


5
.
3
.
2

Android app structure


The client application is consisting of 4 files:


1
.

CommonUtilities.java


This file includes the definitions of

two main variables




SERVER_URL

, the server app url
for e.g.,
http://10.130.201.80:8080/gcm
-
demo




SENDER_ID

, Google API project ID




This file will look like this:





























package

com.google.android.gcm.demo.app;


import

android.content.Context;

import

android.content.Intent;


/**


* Helper class providing methods and constants common to other classes in the


*
app
.


*/

public

final

class

CommonUtilities {



/**


* Base URL of the Demo Server (such as http://my_host:8080/gcm
-
demo)


*/


static

final

String
SERVER_URL

=
"http://10.130.201.80:8080/gcm
-
demo"
;



/**


* Google API project id registered to use GCM.


*/


static

final

String
SENDER_ID

=
"514132917049"
;



/**


* Tag used on log messages.


*/


static

final

String
TAG

=
"GCMDemo"
;



/**


* Intent used to display a message in the screen.


*/


static

final

String
DISPLAY_MESSAGE_ACTION

=


"
com.google.android.gcm.demo.app.DISPLAY_MESSAGE"
;






/**


* Notifies UI to display a message.


*
<p>


* This method is defined in the common helper because it's used both by


* the UI and the background service.


*


*
@param

context application's context.


*
@param

message message to be displayed.


*/


static

void

displayMessage(Context context, String message) {













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
23


















2
.

GCMIntentService.java


This class extends GCMBaseIntentService and it represents
the
intent service responsible for handling GCM messages. In this class
we are
overriding the following callback methods (which are called
by GCMBroadcastReceiver)
:



onRegistered
(Context context, String regId): Called after a
registration intent is received, passes the registration ID
assigned by GCM to that device/application pair as parameter.
Typically, you should send the regid to your server so it can use
it to se
nd messages to this device.



onUnregistered
(Context context, String regId): Called after the
device has been unregistered from GCM. Typically, you should
send the regid to the server so it unregisters the device.



onMessage
(Context context, Intent intent): C
alled when your
server sends a message to GCM, and GCM delivers it to the
device. If the message has a payload, its contents are available
as extras in the intent.



onError
(Context context, String errorId
): Called when the
device tries to register or unregister, but GCM returned an
error. Typically, there is nothing to be done other than
evaluating the error (returned by errorId) and trying to fix the
problem.



onRecoverableError
(Context context, String err
orId): Called
when the device tries to register or unregister, but the GCM


/**


* Intent's extra that contains the message to be displayed.


*/


static

final

String
EXTRA_MESSAGE

=
"message"
;



/**


* Notifies UI to display a message.


*
<p>


* This method is defined in the common helper because it's used both by


* the UI and the background service.


*


*
@param

context application's context.


*
@param

message message to
be displayed.


*/


static

void

displayMessage(Context context, String message) {


Intent intent =
new

Intent(
DISPLAY_MESSAGE_ACTION
);


intent.putExtra(
EXTRA_MESSAGE
, message);


context.sendBroadcast(intent);


}

}













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
24











































Log.
i
(
TAG
,
"Ignoring unregister callback"
);


}


}


@Override


protected

void

onMessage(Context context, Intent intent) {


Log.
i
(
TAG
,
"Received message"
);


String message = getString(R.string.
gcm_message
);


displayMessage
(context, message);


// notifies user with the new messages


generateNotification
(context, message);


}



@Override


protected

void

onDeletedMessages(Context context,
int

total) {


Log.
i
(
TAG
,
"Received deleted messages notification"
);


String message = getString(R.string.
gcm_deleted
, total);


displayMessage
(context, message);


// notifies user


generateNotification
(context, message);


}



@Override


public

void

onError(Context context, String errorId) {


Log.
i
(
TAG
,
"Received error: "

+ errorId);


displayMessage
(context, getString(R.string.
gcm_error
, errorId));


}



@Override


protected

boolean

onRecoverableError(Context context, String errorId) {


// log message


Log.
i
(
TAG
,
"Received recoverable error: "

+ errorId);


displayMessage
(context, getString(R.string.
gcm_recoverable_error
,



errorId));


return

super
.onRecoverableError(context, errorId);


}


/**


* Issues a notification to inform the user that server has sent a message.


*/


private

static

void

generateNotification(Context context, String message) {


int

icon = R.drawable.
ic_stat_gcm
;


long

when = System.
currentTimeMillis
();


NotificationManager notificationManager = (NotificationManager)


context.getSystemService(Context.
NOTIFICATION_SERVICE
);


Notification notification =
new

Notification
(icon, message, when)
;


String title = context.getString(R.string.
app_name
);


Intent notificationIntent =
new

Intent(
"android.intent.action.VIEW"
,


Uri.
parse
(
"http://10.130.201.80:8080/ECWebSec/"
));


// set intent so it does not start a new activity


notificationIntent.setFlags(Intent.
FLAG_ACTIVITY_CLEAR_TOP

|


Intent.
FLAG_ACTIVITY_SINGLE_TOP
);


PendingIntent intent =



PendingIntent.
getActivity
(context, 0, notificationIntent, 0);


notification.
setLatestEventInfo
(context, title, message, intent)
;


notification.
flags

|= Notification.
FLAG_AUTO_CANCEL
;


notificationManager.notify(0,
notification);


}

}














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
25


servers are unavailable. The GCM library will retry the
operation using exponential backup, unless this method is
overridden and returns false. This method is optional and
should be overridden only if you want to display the message to
the user or cancel t
he retry attempts.

This file will look like this:



































package

com.google.android.gcm.demo.app;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
SENDER_ID
;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
displayMessage
;

import

android.app.Notification;

import

android.app.NotificationManager;

import

android.app.PendingIntent;

import

android.content.Context;

import

android.content.Intent;

import

android.net.Uri;

import

android.util.Log;

import

com.google.android.gcm.GCMBaseIntentS
ervice;

import

com.google.android.gcm.GCMRegistrar;


/**


* IntentService responsible for handling GCM messages.


*/


public

class

GCMIntentService
extends

GCMBaseIntentService {



@SuppressWarnings
(
"hiding"
)


private

static

final

String
TAG

=
"
GCMIntentService"
;



public

GCMIntentService() {


super
(
SENDER_ID
);


}



@Override


protected

void

onRegistered(Context context, String registrationId) {


Log.
i
(
TAG
,
"Device registered: regId = "

+ registrationId);


displayMessage
(context, getString(R.string.
gcm_registered
));


ServerUtilities.
register
(context, registrationId);


}


@Override


protected

void

onUnregistered(Context context, String registrationId) {


Log.
i
(
TAG
,
"Device unregistered"
);


displayMessage
(context, getString(R.string.
gcm_unregistered
));


if

(GCMRegistrar.
isRegisteredOnServer
(context)) {


ServerUtilities.
unregister
(context, registrationId);

}
else

{


// This callback results from the call

to unregister made on


// ServerUtilities when the registration to the server failed.














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
26


3
.

ServerUtilities.java


This is a helper class used to enable the Android app to
communicate with the application server. It
contains three
methods called:




register()

Posts the registration request to the register servlet
deployed at the application server, this servlet accepts the
request and stores the registration id in its database.



unregister()

Posts the unregister request to the unregister servlet
deployed at the application
server, this servlet accepts the
request and removes the registration id from its

database.



Post()

Posts the register or unregister request to the application
server

This
file will look like this:

























How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
27



















package

com.google.android.gcm.demo.app;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
SERVER_URL
;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
TAG
;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
displayMessage
;

import

com.google.android.gcm.GCMRegistrar;

import

android.content.Context;

import

android.util.Log;

import

java.io.IOException;

import

java.io.OutputStream;

import

java.net.HttpURLConnection;

import

java.net.MalformedURLException;

import

java.net.URL;

import

java.util.HashMap;

import

java.util.Iterator;

import

java.util.Map;

import

java.util.Map.Entry;

import

java.util.Random;


/**


* Helper class used to communicate with the demo server.


*/

public

final

class

ServerUtilities {



private

static

final

int

MAX_ATTEMPTS

= 5;


private

static

final

int

BACKOFF_MILLI_SECONDS

= 2000;


private

static

final

Random
random

=
new

Random();



/**


* Register this account/device pair within the server.


*


*
@return

whether the registration succeeded or not.


*/


static

boolean

register(
final

Context context,
final

String regId) {


Log.
i
(
TAG
,
"registering device (regId = "

+ regId +
")"
);


String serverUrl =
SERVER_URL

+
"/register"
;


Map<String, String> params =
new

HashMap<String, String>();


params.put(
"regId"
, regId);


long

backoff =
BACKOFF_MILLI_SECONDS

+
random
.nextInt(1000);


for

(
int

i = 1; i <=
MAX_ATTEMPTS
; i++) {


Log.
d
(
TAG
,
"Attempt #"

+ i +
" to register"
);


try

{


displayMessage
(context, context.getString(


R.string.
server_registering
, i,
MAX_ATTEMPTS
));


post
(serverUrl, params);


GCMRegistrar.
setRegisteredOnServer
(context,
true
);


String message = context.getString(R.string.
server_registered
);


CommonUtilities.
displayMessage
(context, message);



return

true
;


}
catch

(IOException e) {


Log.
e
(
TAG
,
"Failed to register on attempt "

+ i, e);


if

(i ==
MAX_ATTEMPTS
) {


break
;


}


try

{


Log.
d
(
TAG
,
"Sleeping for "

+ backoff +
" ms before retry"
);


Thread.
sleep
(backoff);


}
catch

(InterruptedException e1) {


// Activity finished before we complete
-

exit.



Log.
d
(
TAG
,
"Thread interrupted: abort remaining retries!"
);


Thread.
currentThread
().interrupt();


return

false
;


}


// increase
backoff

exponentially


backoff *= 2;


}


}


String message = context.getString(R.string.
server_register_error
,













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
28

























Log.
d
(
TAG
,
"Thread interrupted: abort remaining
retries!"
);


Thread.
currentThread
().interrupt();


return

false
;


}


// increase
backoff

exponentially


backoff *= 2;


}


}


String message = context.getString(R.string.
server_register_error
,


MAX_ATTEMPTS
);


CommonUtiliti
es.
displayMessage
(context, message);


return

false
;


}



/**


* Unregister this account/device pair within the server.


*/


static

void

unregister(
final

Context context,
final

String regId) {


Log.
i
(
TAG
,
"unregistering device

(regId = "

+ regId +
")"
);


String serverUrl =
SERVER_URL

+
"/unregister"
;


Map<String, String> params =
new

HashMap<String, String>();


params.put(
"regId"
, regId);


try

{


post
(serverUrl, params);


GCMRegistrar.
setRegisteredOnServer
(context,
false
);


String message =






context.getString(R.string.
server_unregistered
);


CommonUtilities.
displayMessage
(context, message);


}
catch

(IOException e) {


// At this
point the device is unregistered from GCM, but still


// registered in the server.


// We could try to unregister again, but it is not necessary:


// if the server tries to send a message to the device, it will



get



// a "NotRegistered" error message and should unregister the



device.


String message =
context.getString(R.string.
server_unregister_error
,


e.getMessage());


CommonUtilities.
displayMessage
(context, m
essage);


}


}














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
29









































1
.

DemoActivity.java


This class is the main UI of the application; it handles the
registration of the Android device when the activity starts




/**


* Issue a POST request to the server.


*


*
@param

endpoint POST address.


*
@param

params request parameters.


*


*
@throws

IOException propagated from POST.


*/


private

static

void

post(
String

endpoint, Map<
String
,
String
> params)


throws

IOException {


URL url;


try

{


url =
new

URL(endpoint);


}
catch

(MalformedURLException e) {


throw

new

IllegalArgumentException(
"invalid url: "

+ endpoint);


}


StringBuilder bodyBuilder =
new

StringBuilder();


Iterator<Entry<
String
,
String
>> iterator = params.entrySet().iterator();


// constructs the POST body using the
parameters


while

(iterator.hasNext()) {


Entry<
String
,
String
> param = iterator.next();


bodyBuilder.append(param.getKey()).append(
'='
)


.append(param.getValue());


if

(iterator.hasNext()) {


bodyBuilder.append(
'&'
);


}


}


String

body = bodyBuilder.toString();


Log.
v
(
TAG
,
"Posting '"

+ body +
"' to "

+ url);


byte
[] bytes = body.getBytes();


HttpURLConnection conn =
null
;


try

{


conn = (HttpURLConnection) url.openConnection();


conn.setDoOutput(
true
);


conn.setUseCaches(
false
);


conn.setFixedLengthStreamingMode(bytes.
length
);


conn.setRequestMethod(
"POST"
);


conn.setRequestProperty(
"Content
-
Type"
,


"application/x
-
www
-
form
-
urlencoded;charset=UTF
-
8"
);


// post the request


OutputStream out = conn.getOutputStream();


out.write(bytes);


out.close();



// handle the response


int

status = conn.getResponseCode();


if

(status != 200) {


Log.
d
(
TAG
,
"Post failed with error code"
);


throw

new

IOException(
"Post failed with error code "

+ status);


}


}
finally

{


if

(conn !=
null
) {


conn.disconnect();


}


}


}

}














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
30


4
.

DemoActivity.java


This class is the main UI of the application; it handles the
registration of the Android device when the activity starts


4
.
1

Application registration:

An Android application need
s to register with GCM servers before
it can receive messages. To register, the application sends
Intent

(
com.google.android.c2dm.intent.REGISTER
), with 2 extra
parameters:

o

Sender

is the project number of the account
authorized to send messages to the Android
application.

o

App

is the Android application's ID, set with a
PendingIntent to allow the registration service to
extract Android application information.


This registration
can be done easily using the GCMRegstrar object







GCMRegistrar.register(this, SENDER_ID);


This intent will be asynchronously sent to the GCM server, and the
response will be delivered to the application as a
com.google.android.c2dm.intent.REGISTRATION

intent containing
the registration ID assigned to the Android application running on
that particular device.


Registration is not complete until the Android application sends
the registration ID to the 3rd
-
party application server, which in
turn will use the registration ID to send messages to the
application. This is done by calling




ServerUtilities.register(context, regId);



4
.
2

Handling GCM intents:


The manifest defines a broadcast receiver for the

com.google.android.c2dm.intent.REGISTRATION

and
com.google.android.c2dm.intent.RECEIVE

intents. These
intents

are
sent by GCM to indicate that a device was registered (or
unregistered), or to deliver messages, respectively.














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
31


Handling these intents might require I/O operations (s
uch as
network calls to

the 3rd party server), and such operations should
not be done in the receiver's onReceive() method.
T
he
recommended way to handle the intents is to delegate them to a
service, such as
a

GCM
IntentService

explained above
.


This file will look like this:








package

com.google.android.gcm.demo.app;


import

static

com.google.android.gcm.demo.app.CommonUtilities.
DISPLAY_MESSAGE_ACTION
;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
EXTRA_MESSAGE
;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
SENDER_ID
;

import

static

com.google.android.gcm.demo.app.CommonUtilities.
SERVER_URL
;


import

com.google.android.gcm.GCMRegistrar;


import

android.app.Activity;

import

android.content.BroadcastReceiver;

import

android.content.Context;

import

android.content.Intent;

import

android.content.IntentFilter;

import

android.graphics.Color;

import

android.net.Uri;

import

android.os.AsyncTask;

import

android.os.Bundle;

import

android.util.Log;

import

android.view.Menu;

import

android.view.MenuInflater;

import

android.view.MenuItem;

import

android.view.View;

import

android.widget.Button;

import

android.widget.TextView;


/**


* Main UI for the dem
o
app
.


*/

public

class

DemoActivity
extends

Activity {



TextView
mDisplay
;


Button
webSiteButton
;


AsyncTask<Void, Void, Void>
mRegisterTask
;


private

static

final

String
TAG

=
"Activity"
;



@Override


public

void

onCreate(Bundle
savedInstanceState) {


super
.onCreate(savedInstanceState);


checkNotNull(
SERVER_URL
,
"SERVER_URL"
);


checkNotNull(
SENDER_ID
,
"SENDER_ID"
);


// Make sure the device has the proper dependencies.


GCMRegistrar.
checkDevice
(
this
);


// Make sure the manifest was properly set
-

comment out this line


// while developing the
app
, then
uncomment

it when it's ready.


GCMRegistrar.
checkManifest
(
this
);


setContentView(R.layout.
main
);




webSiteButton
=(Button)findViewById(R.id.
WebSiteButton
);


webSiteButton
.setOnClickListener(
new

View.OnClickListener(){




public

void

onClick(View v){













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
32
























// Make sure the device has the proper
dependencies.


GCMRegistrar.
checkDevice
(
this
);


// Make sure the manifest was properly set
-

comment out this line





GCMRegistrar.
checkManifest
(
this
);


setContentView(R.layout.
main
);




webSiteButton
=(Button)
findViewById(R.id.
WebSiteButton
);


webSiteButton
.setOnClickListener(
new

View.OnClickListener(){




public

void

onClick(View v){




Intent intent =
new

Intent();




intent.setAction(Intent.
ACTION_VIEW
);




intent.a
ddCategory(Intent.
CATEGORY_BROWSABLE
);




intent.setData(Uri.
parse
(
"http://10.130.201.80:8080/ECWebSec/"
));




startActivity(intent);




}



});




mDisplay

= (TextView) findViewById(R.id.
display
);


mDisplay
.setText(
"
\
nSmart Home Notifier Application will send you a
notifications in case of "

+

"faults occured with your home devices."

+

"The application is based on Google Cloud Messaging Service (GCM).
\
n"

+

"The scenario is as follow:
\
n"

+
"


1
-

In cas
e of fault occured, a fault
detector web service will be invoked. This web service sends the fault message to
the GCM server via a web application deployed in the application server
\
n"

+




"


2
-

The GCM server receives the message and routes
it to
the target Application which is running on your device.
\
n"

+

"**Developed by: SECC R&D Team. www.secc.org.eg
\
n
\
n
\
n"
);




mDisplay
.setTextColor(Color.
WHITE
);


mDisplay
.append(
"Log:"
);


registerReceiver(
mHandleMessageReceiver
,


new

IntentFilter(
DISPLAY_MESSAGE_ACTION
));


final

String regId = GCMRegistrar.
getRegistrationId
(
this
);


if

(regId.equals(
""
)) {


// Automatically registers application on startup.


GCMRegistrar.
register
(
this
,
SENDER_ID
);


Log.
d
(
TAG
,
"Registered to GCM !!! "
);



}
else

{


// Device is already registered on GCM, check server.


if

(GCMRegistrar.
isRegisteredOnServer
(
this
)) {


// Skips registration.


mDisplay
.append(getString(R.string.
already_registered
) +
"
\
n"
);


}
else

{


// Try to register again, but not in the UI thread.


// It's also necessary to cancel the thread onDestroy(),



// hence the use of AsyncTask instead of a raw thread.


final

Context context =
this
;


mRegisterTask

=
new

AsyncTask<Void, Void, Void>() {



@Override


protected

Void doInBackground
(Void... params) {


boolean

registered =


ServerUtilities.
register
(context, regId);







if

(!registered) {



GCMRegistrar.
unregister
(context);


}


return

null
;


}



@Override


protected

void

onPostExecute(Void result) {


mRegisterTask

=
null
;













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
33























if

(!registered) {


GCMRegistrar.
unregister
(context);


}


return

null
;


}



@Override


protected

void

onPostExecute(Void result) {


mRegisterTask

=
null
;


}



};


mRegisterTask
.execute(
null
,
null
,
null
);


}


}


}



@Override


public

boolean

onCreateOptionsMenu(Menu menu) {


MenuInflater inflater = getMenuInflater();


inflater.inflate(R.menu.
options_menu
, menu);


return

true
;


}


@Override


public

boolean

onOptionsItemSelected(MenuItem item) {


switch
(item.getItemId()) {




case

R.id.
options_clear
:


mDisplay
.setText(
null
);


return

true
;


case

R.id.
options_exit
:


finish();


return

true
;


default
:


return

super
.onOptionsItemSelected(item);


}


}



@Override


protected

void

onDestroy() {


if

(
mRegisterTask

!=
null
) {


mRegisterTask
.cancel(
true
);


}


unregisterReceiver(
mHandleMessageReceiver
);


GCMRegistrar.
onDestroy
(
this
);


super
.onDestroy();


}













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
34











After developing the above application, you can now run the project to get the


.apk file and install it in your Android
-
powered device
. When running this



application you will see a screen like this:




























N.B: You must make sure that the application server app (gc
-
demo
-
server.war) is


deployed and running on tomcat

6
.

Invoker
Application


Up till now, you have both
Android and the Application server

apps running. In
order to test the whole cycle you

ll need

to

develop an invoker application that

private

void

checkNotNull(Object reference, String name) {


if

(reference ==
null
) {


throw

new

NullPointerException(


getString(R.string.
error_config
, name));


}


}



private

final

BroadcastReceiver
mHandl
eMessageReceiver

=


new

BroadcastReceiver() {


@Override


public

void

onReceive(Context context, Intent intent) {


String newMessage = intent.getExtras().getString(
EXTRA_MESSAGE
);


mDisplay
.append(newMessage

+
"
\
n"
);


}


};


}













How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
35


calls

the application server app and asks it to send a message to the Android app
.
O
nce this message is received, the Android app will fire a notification fo
r the
user. In the practical case
s
, this invoker app is your end application that needs
based on some logic to send notifications to the Android
-
powered device.

6
.
1
.

Invoker example architecture




The invoker explained in this tutorial is composed of two

files
:


1
.

Definitions.java




This file is simply

contains the project ID, it will look as follow:
















2
.

InvokeSendAllServlet.java


This file is
the core invoker which calls the sendAll servlet

of the application
server which is responsible for contacting the GCM server and asking it to send
messages to the Android application
. This file could be like this:















package

com.secc.SendNotificationViaGCMService;


public

final

class

Definitions {



static

final

String
SERVER_URL

=
"http://10.130.201.80:8080/gcm
-
demo"
;



/**


* Google API project id registered to use GCM.


*/


static

final

String
SENDER_ID

=
"514132917049"
;

}














How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
36

















































package com.secc.SendNotificationViaGCMService;

import static
com.secc.SendNotificationViaGCMService.Definitions.SERVER_URL;

import java.io.IOException;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.MalformedURLException;

import java.net.URL;


public class InvokeSendAllServlet {




public void invokeSendAllServlet() {



String serverUrl = SERVER_URL + "/sendAll";


try {


post(serverUrl);


} catch (IOException e) {


}


}

private static void post(String endpoint)


throws IOException {


URL url;


try {


url = new URL(endpoint);


} catch (MalformedURLException e) {


throw new IllegalArgumentException("invalid url: " + endpoint);


}


HttpURLConnection conn = null;


try {


conn = (Ht
tpURLConnection) url.openConnection();


conn.setDoOutput(true);


conn.setUseCaches(false);


conn.setRequestMethod("POST");


conn.setRequestProperty("Content
-
Type",


"application/x
-
www
-
form
-
urlencoded;charset=UTF
-
8");


OutputStream out = conn.getOutputStream();


out.close();


int status = conn.getResponseCode();


if (status != 200) {


throw new IOException("Post failed with error code "

+ status);


}


} finally {


if (conn != null) {


conn.disconnect();


}


}


}


public static void main(String []args) {



InvokeSendAllServlet invoke=new InvokeSendAllServlet();



invoke.invokeSendAllServlet();


}

}















How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
37




By
running

the above invoker
app
you should see a notification appeared.



7
.

Summary


Google Cloud Messaging for Android (GCM) is a free

and powerful

service that
helps developers
to
send data from servers to their Android applications
running
on Android
-
powered

devices
.

This tutorial
provides

the basic concepts
of this service with a detailed explanation of the GCM demo application provided
by the Android SDK. The GCM service is very promising and it

could

be












How To

Develop Smart Android Notifications using Google Cloud Messaging Service
| Tutorial

Page
38


considered

the

most optimized and powerful method for sending
messages

from
servers t
o the Android devices

without the need to have the
Android

application
listens to the server in an endless loop
.

8
.

References


[
1
]

http://developer.android.com/google/gcm/gs.html

[
2
]

http://developer.android.com/google/gcm/gcm.html

[
3
]

http://developer.android.com/google/gcm/demo.html

9
.

Abbreviations


GCM


Google Cloud

Messaging

App

Application

HTTP

Hypertext Transfer Protocol

API

Application Programming Interface

C2DM

Cloud to Device Messaging

KP

Knowledge Processor