1page.title=Implementing GCM Client on Android
2page.tags=cloud,push,messaging
3@jd:body
4
5<div id="qv-wrapper">
6<div id="qv">
7
8
9<h2>In this document</h2>
10
11<ol class="toc">
12<li><a href="#play-services">Set Up Google Play Services</a></li>
13<li><a href="#manifest">Edit Your Application's Manifest</a></li>
14<li><a href="#app">Write Your Application</a>
15  <ol class="toc">
16    <li><a href="#sample-play">Check for Google Play Services APK</a></li>
17    <li><a href="#sample-register">Register for GCM</a></li>
18    <li><a href="#sample-receive">Receive a downstream message</a></li>
19    <li><a href="#sample-send">Send an upstream message</a></li>
20  </ol>
21  <li><a href="#run">Running the Sample</a></li>
22  <li><a href="#stats">Viewing Statistics</a></li>
23</li>
24
25</ol>
26
27<h2>See Also</h2>
28
29<ol class="toc">
30<li><a href="gs.html">Getting Started</a></li>
31<li><a href="server.html">Implementing GCM Server</a></li>
32</ol>
33
34</div>
35</div>
36
37<p>A Google Cloud Messaging (GCM) Android client is a GCM-enabled app that runs on an
38Android device. To write your client code, we recommend that you use the
39<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
40{@code GoogleCloudMessaging}</a> API.</p>
41
42<p>Here are the requirements for running a GCM Android client:</p>
43
44<ul>
45  <li>At a bare minimum, GCM requires devices running Android 2.2 or higher that also have the
46Google Play Store application installed, or an emulator running Android 2.2
47with Google APIs. Note that you are not limited to deploying your
48Android applications through Google Play Store.</li>
49  <li>However, if you want to continue to use new GCM features that are distributed
50through Google Play Services, the device must be running Android 2.3 or higher, or
51you can use an emulator running Android 2.3 with Google APIs.</li>
52<li>On Android devices, GCM uses an existing connection for Google services. For
53pre-3.0 devices, this requires users to set up their Google accounts on their mobile
54devices. A Google account is not a requirement on devices running Android 4.0.4 or higher.</li>
55
56</ul>
57
58<p>A full GCM implementation requires both a client implementation and a server
59implementation. For more
60information about implementing the server side, see <a href="server.html">
61Implementing GCM Server</a>.</p>
62
63<p>The following sections walk you through the steps involved in writing a GCM
64client-side application. Your client app can be arbitrarily complex, but at bare
65minimum, a GCM client app must include code to register (and thereby get a
66registration ID), and a broadcast receiver to receive messages sent by GCM.
67</p>
68
69<h2 id="play-services">Step 1: Set Up Google Play Services</h2>
70
71<p>To write your client application, use the
72<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
73{@code GoogleCloudMessaging}</a> API.
74To use this API, you must set up your project to use the Google Play services SDK,
75as described in <a href="/google/play-services/setup.html">Setup Google Play
76Services SDK</a>.</p>
77
78<p class="note"><strong>Caution:</strong> When you add the Play Services library to
79your project, be sure to add it <em>with resources</em>, as described in
80<a href="{@docRoot}google/play-services/setup.html#Setup">
81Setup Google Play Services SDK</a>. The key point is that you must
82<em>reference</em> the library&mdash;simply adding a {@code .jar} file to
83your Eclipse project will not work. You must follow the directions
84for referencing a library, or your app won't be able to access
85the library's resources, and it won't run properly.
86If you're using Android Studio, this is the string to add to the
87{@code dependency} section of your application's {@code build.gradle} file:</p>
88
89<pre>dependencies {
90  compile "com.google.android.gms:play-services:3.1.+"
91}
92</pre>
93
94
95<h2 id="manifest">Step 2: Edit Your Application's Manifest</h2>
96
97<p>Add the following to your application's manifest:</p>
98<ul>
99  <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so
100the Android application can register and receive messages.</li>
101  <li>The <code>android.permission.INTERNET</code> permission so the Android
102application can send the registration ID to the 3rd party server.</li>
103  <li>The <code>android.permission.WAKE_LOCK</code> permission so the application
104can keep the processor from sleeping when a message is received. Optional&mdash;use
105only if the app wants to keep the device from sleeping.</li>
106  <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code>
107permission to prevent other Android applications from registering and receiving
108the Android application's messages. The permission name must exactly match this
109pattern&mdash;otherwise the Android application will not receive the messages.</li>
110   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with
111the category set
112as <code>applicationPackage</code>. The receiver should require the
113<code>com.google.android.c2dm.permission.SEND</code> permission, so that only the GCM
114Framework can send a message to it. If your app uses an {@link android.app.IntentService}
115(not required, but a common pattern), this receiver should be an instance of
116{@link android.support.v4.content.WakefulBroadcastReceiver}.
117A {@link android.support.v4.content.WakefulBroadcastReceiver} takes care of
118creating and managing a
119<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
120partial wake lock</a> for your app.</li>
121
122<li>A {@link android.app.Service} (typically an {@link android.app.IntentService})
123to which the {@link android.support.v4.content.WakefulBroadcastReceiver} passes off
124the work of handling the GCM message, while ensuring that the device does not
125go back to sleep in the process. Including an {@link android.app.IntentService} is
126optional&mdash;you could choose to process your messages in a regular
127{@link android.content.BroadcastReceiver} instead, but realistically, most apps will
128use a {@link android.app.IntentService}.
129</li>
130  <li>If the GCM feature is critical to the Android application's function, be sure to
131set <code>android:minSdkVersion=&quot;8&quot;</code> or higher in the manifest. This
132ensures that the Android application cannot be installed in an environment in which it
133could not run properly. </li>
134</ul>
135
136<p>Here are excerpts from a sample manifest that supports GCM:</p>
137
138<pre class="prettyprint pretty-xml">
139&lt;manifest package="com.example.gcm" ...&gt;
140
141    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
142    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
143    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
144    &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
145    &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
146
147    &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE"
148        android:protectionLevel="signature" /&gt;
149    &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
150
151    &lt;application ...&gt;
152        &lt;receiver
153            android:name=".GcmBroadcastReceiver"
154            android:permission="com.google.android.c2dm.permission.SEND" &gt;
155            &lt;intent-filter&gt;
156                &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
157                &lt;category android:name="com.example.gcm" /&gt;
158            &lt;/intent-filter&gt;
159        &lt;/receiver&gt;
160        &lt;service android:name=".GcmIntentService" /&gt;
161    &lt;/application&gt;
162
163&lt;/manifest&gt;
164</pre>
165
166<h2 id="app"> Step 3: Write Your Application</h2>
167
168<p>Finally, write your application. This section features a sample client
169application that illustrates how to use the
170<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
171{@code GoogleCloudMessaging}</a> API. The sample consists of a main activity
172({@code DemoActivity}), a {@link android.support.v4.content.WakefulBroadcastReceiver}
173({@code GcmBroadcastReceiver}), and an {@link android.app.IntentService}
174({@code GcmIntentService}). You can find the complete source code for this sample at the
175<a href="http://code.google.com/p/gcm">open source site</a>.</p>
176
177<p>Note the following:</p>
178
179<ul>
180  <li>Among other things, the sample illustrates registration and upstream
181(device-to-cloud) messaging. Upstream messaging only applies to apps that are running against a
182<a href="ccs.html">CCS</a> (XMPP) server; HTTP-based servers don't support upstream messaging.</li>
183  <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
184  {@code GoogleCloudMessaging}</a>
185registration APIs replace the old registration process, which was based on the
186now-obsolete client helper library. While the old registration process still works,
187we encourage you to use the newer
188<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
189{@code GoogleCloudMessaging}</a>
190registration APIs, regardless of your underlying server.</li>
191</ul>
192
193<h3 id="sample-play">Check for Google Play Services APK</h3>
194
195<p>As described in <a href="{@docRoot}google/play-services/setup.html">
196Setup Google Play Services SDK</a>, apps that rely on the Play Services SDK
197should always check the device for a compatible Google Play services APK before
198accessing Google Play services features. In the sample app this check is done in
199two places: in the main activity's {@code onCreate()} method, and in its
200{@code onResume()} method. The check in {@code onCreate()} ensures that the app
201can't be used without a successful check. The check in {@code onResume()} ensures
202that if the user returns to the running app through some other means, such as
203through the back button, the check is still performed. If the
204device doesn't have a compatible Google Play services APK, your app can call
205{@code GooglePlayServicesUtil.getErrorDialog()} to allow users to download the
206APK from the Google Play Store or enable it in the device's system settings.
207For example:</p>
208
209<pre>private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
210...
211&#64;Override
212public void onCreate(Bundle savedInstanceState) {
213    super.onCreate(savedInstanceState);
214
215    setContentView(R.layout.main);
216    mDisplay = (TextView) findViewById(R.id.display);
217
218    context = getApplicationContext();
219
220    // Check device for Play Services APK.
221    if (checkPlayServices()) {
222        // If this check succeeds, proceed with normal processing.
223        // Otherwise, prompt user to get valid Play Services APK.
224        ...
225    }
226}
227
228// You need to do the Play Services APK check here too.
229&#64;Override
230protected void onResume() {
231    super.onResume();
232    checkPlayServices();
233}
234
235/**
236 * Check the device to make sure it has the Google Play Services APK. If
237 * it doesn't, display a dialog that allows users to download the APK from
238 * the Google Play Store or enable it in the device's system settings.
239 */
240private boolean checkPlayServices() {
241    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
242    if (resultCode != ConnectionResult.SUCCESS) {
243        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
244            GooglePlayServicesUtil.getErrorDialog(resultCode, this,
245                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
246        } else {
247            Log.i(TAG, "This device is not supported.");
248            finish();
249        }
250        return false;
251    }
252    return true;
253}</pre>
254
255<h3 id="sample-register">Register for GCM</h3>
256<p>An Android application needs to register with GCM servers before it can receive
257messages. When an app registers, it receives a registration ID, which it can then
258store for future use (note that registration IDs must be kept secret). In the
259following snippet the {@code onCreate()} method in the sample app's
260main activity checks to see if the app is already registered with GCM and with
261the server:</p>
262
263<pre>/**
264 * Main UI for the demo app.
265 */
266public class DemoActivity extends Activity {
267
268    public static final String EXTRA_MESSAGE = "message";
269    public static final String PROPERTY_REG_ID = "registration_id";
270    private static final String PROPERTY_APP_VERSION = "appVersion";
271    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
272
273    /**
274     * Substitute you own sender ID here. This is the project number you got
275     * from the API Console, as described in "Getting Started."
276     */
277    String SENDER_ID = "Your-Sender-ID";
278
279    /**
280     * Tag used on log messages.
281     */
282    static final String TAG = "GCMDemo";
283
284    TextView mDisplay;
285    GoogleCloudMessaging gcm;
286    AtomicInteger msgId = new AtomicInteger();
287    SharedPreferences prefs;
288    Context context;
289
290    String regid;
291
292    &#64;Override
293    public void onCreate(Bundle savedInstanceState) {
294        super.onCreate(savedInstanceState);
295
296        setContentView(R.layout.main);
297        mDisplay = (TextView) findViewById(R.id.display);
298
299        context = getApplicationContext();
300
301        // Check device for Play Services APK. If check succeeds, proceed with
302        //  GCM registration.
303        if (checkPlayServices()) {
304            gcm = GoogleCloudMessaging.getInstance(this);
305            regid = getRegistrationId(context);
306
307            if (regid.isEmpty()) {
308                registerInBackground();
309            }
310        } else {
311            Log.i(TAG, "No valid Google Play Services APK found.");
312        }
313    }
314...
315}</pre>
316
317<p>The app calls {@code getRegistrationId()} to see whether there is an existing
318registration ID stored in shared preferences:</p>
319
320<pre>/**
321 * Gets the current registration ID for application on GCM service.
322 * &lt;p&gt;
323 * If result is empty, the app needs to register.
324 *
325 * &#64;return registration ID, or empty string if there is no existing
326 *         registration ID.
327 */
328private String getRegistrationId(Context context) {
329    final SharedPreferences prefs = getGCMPreferences(context);
330    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
331    if (registrationId.isEmpty()) {
332        Log.i(TAG, "Registration not found.");
333        return "";
334    }
335    // Check if app was updated; if so, it must clear the registration ID
336    // since the existing registration ID is not guaranteed to work with
337    // the new app version.
338    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
339    int currentVersion = getAppVersion(context);
340    if (registeredVersion != currentVersion) {
341        Log.i(TAG, "App version changed.");
342        return "";
343    }
344    return registrationId;
345}
346...
347/**
348 * &#64;return Application's {&#64;code SharedPreferences}.
349 */
350private SharedPreferences getGCMPreferences(Context context) {
351    // This sample app persists the registration ID in shared preferences, but
352    // how you store the registration ID in your app is up to you.
353    return getSharedPreferences(DemoActivity.class.getSimpleName(),
354            Context.MODE_PRIVATE);
355}</pre>
356
357<p>If the registration ID doesn't exist or the app was updated,
358{@code getRegistrationId()} returns an empty string
359to indicate that the app needs to get a new registration ID. {@code getRegistrationId()} calls
360the following method to check the app version:</p>
361
362<pre>/**
363 * &#64;return Application's version code from the {&#64;code PackageManager}.
364 */
365private static int getAppVersion(Context context) {
366    try {
367        PackageInfo packageInfo = context.getPackageManager()
368                .getPackageInfo(context.getPackageName(), 0);
369        return packageInfo.versionCode;
370    } catch (NameNotFoundException e) {
371        // should never happen
372        throw new RuntimeException("Could not get package name: " + e);
373    }
374}</pre>
375
376
377<p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the
378following {@code registerInBackground()} method to register. Note that because the GCM
379methods {@code register()} and {@code unregister()} are blocking, this has to
380take place on a background thread. This sample uses {@link android.os.AsyncTask}
381to accomplish this:</p>
382
383<pre>
384/**
385 * Registers the application with GCM servers asynchronously.
386 * &lt;p&gt;
387 * Stores the registration ID and app versionCode in the application's
388 * shared preferences.
389 */
390private void registerInBackground() {
391    new AsyncTask<Void, Void, String>() {
392        &#64;Override
393        protected String doInBackground(Void... params) {
394            String msg = "";
395            try {
396                if (gcm == null) {
397                    gcm = GoogleCloudMessaging.getInstance(context);
398                }
399                regid = gcm.register(SENDER_ID);
400                msg = "Device registered, registration ID=" + regid;
401
402                // You should send the registration ID to your server over HTTP,
403                // so it can use GCM/HTTP or CCS to send messages to your app.
404                // The request to your server should be authenticated if your app
405                // is using accounts.
406                sendRegistrationIdToBackend();
407
408                // For this demo: we don't need to send it because the device
409                // will send upstream messages to a server that echo back the
410                // message using the 'from' address in the message.
411
412                // Persist the registration ID - no need to register again.
413                storeRegistrationId(context, regid);
414            } catch (IOException ex) {
415                msg = "Error :" + ex.getMessage();
416                // If there is an error, don't just keep trying to register.
417                // Require the user to click a button again, or perform
418                // exponential back-off.
419            }
420            return msg;
421        }
422
423        &#64;Override
424        protected void onPostExecute(String msg) {
425            mDisplay.append(msg + "\n");
426        }
427    }.execute(null, null, null);
428    ...
429}</pre>
430
431<p>Once you've received your registration ID, send it to your server:</p>
432<pre>
433/**
434 * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
435 * or CCS to send messages to your app. Not needed for this demo since the
436 * device sends upstream messages to a server that echoes back the message
437 * using the 'from' address in the message.
438 */
439private void sendRegistrationIdToBackend() {
440    // Your implementation here.
441}</pre>
442
443<p>After registering, the app calls {@code storeRegistrationId()} to store the
444registration ID in shared preferences for future use. This is just one way of
445persisting a registration ID. You might choose to use a different approach in
446your app:</p>
447
448<pre>/**
449 * Stores the registration ID and app versionCode in the application's
450 * {&#64;code SharedPreferences}.
451 *
452 * &#64;param context application's context.
453 * &#64;param regId registration ID
454 */
455private void storeRegistrationId(Context context, String regId) {
456    final SharedPreferences prefs = getGCMPreferences(context);
457    int appVersion = getAppVersion(context);
458    Log.i(TAG, "Saving regId on app version " + appVersion);
459    SharedPreferences.Editor editor = prefs.edit();
460    editor.putString(PROPERTY_REG_ID, regId);
461    editor.putInt(PROPERTY_APP_VERSION, appVersion);
462    editor.commit();
463}</pre>
464
465<h4 id="reg-errors">Handle registration errors</h4>
466
467<p>As stated above, an Android app must register with GCM servers and get a registration ID
468before it can receive messages. A given registration ID is not guaranteed to last indefinitely,
469so the first thing your app should always do is check to make sure it has a valid
470registration ID (as shown in the code snippets above).</p>
471
472<p>In addition to confirming that it has a valid registration ID, your app should be prepared to handle
473the registration error {@code TOO_MANY_REGISTRATIONS}. This error indicates that the device
474has too many apps registered with GCM. The error only occurs in cases where there are
475extreme numbers of apps, so it should not affect the average user. The remedy is to prompt
476the user to delete some of the other client apps from the device to make
477room for the new one.</p>
478
479<h3 id="sample-receive">Receive a downstream message</h3>
480
481<p>As described above in <a href="#manifest">Step 2</a>, the app includes a
482{@link android.support.v4.content.WakefulBroadcastReceiver} for the <code>com.google.android.c2dm.intent.RECEIVE</code>
483intent. A broadcast receiver is the mechanism GCM uses to deliver messages. </p>
484<p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
485broadcast receiver that takes care of
486creating and managing a
487<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
488partial wake lock</a> for your app.
489It passes off the work of processing the GCM message to a
490{@link android.app.Service} (typically an
491{@link android.app.IntentService}), while ensuring that the device does not
492go back to sleep in the transition. If you don't hold a wake lock while transitioning
493the work to a service, you are effectively allowing the device to go back to sleep before
494the work completes. The net result is that the app might not finish processing
495the GCM message until some arbitrary point in the future, which is not what you want.</p>
496
497<p class="note"><strong>Note:</strong> Using {@link android.support.v4.content.WakefulBroadcastReceiver}
498is not a requirement. If you have a relatively simple app that doesn't require
499a service, you can intercept the GCM message in a regular {@link android.content.BroadcastReceiver}
500and do your processing there. Once you get the intent that GCM passes into
501your broadcast receiver's {@code onReceive()} method, what you do with it
502is up to you.</p>
503
504<p>This snippet starts {@code GcmIntentService} with the method
505{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}.
506This method is comparable to {@link android.content.Context#startService startService()}, except that
507the {@link android.support.v4.content.WakefulBroadcastReceiver} is holding a
508wake lock when the service starts. The intent that is passed with
509{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}
510holds an extra identifying the wake lock:</p>
511
512
513<pre>public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
514    &#64;Override
515    public void onReceive(Context context, Intent intent) {
516        // Explicitly specify that GcmIntentService will handle the intent.
517        ComponentName comp = new ComponentName(context.getPackageName(),
518                GcmIntentService.class.getName());
519        // Start the service, keeping the device awake while it is launching.
520        startWakefulService(context, (intent.setComponent(comp)));
521        setResultCode(Activity.RESULT_OK);
522    }
523}</pre>
524
525<p>The intent service shown below does the actual work of handling the GCM
526message. When the service is finished, it calls
527{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent GcmBroadcastReceiver.completeWakefulIntent()}
528to release the wake lock. The
529{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent completeWakefulIntent()}
530method has as its parameter the same intent that was
531passed in from the {@link android.support.v4.content.WakefulBroadcastReceiver}.
532</p>
533
534<p>This snippet processes the GCM message based on message type, and posts the
535result in a notification. But what you do with GCM messages in your app is up to
536you&mdash;the possibilities are endless. For example, the message might be a ping,
537telling the app to sync to a server to retrieve new content, or it might be a
538chat message that you display in the UI.</p>
539
540<pre>
541public class GcmIntentService extends IntentService {
542    public static final int NOTIFICATION_ID = 1;
543    private NotificationManager mNotificationManager;
544    NotificationCompat.Builder builder;
545
546    public GcmIntentService() {
547        super("GcmIntentService");
548    }
549
550    &#64;Override
551    protected void onHandleIntent(Intent intent) {
552        Bundle extras = intent.getExtras();
553        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
554        // The getMessageType() intent parameter must be the intent you received
555        // in your BroadcastReceiver.
556        String messageType = gcm.getMessageType(intent);
557
558        if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
559            /*
560             * Filter messages based on message type. Since it is likely that GCM
561             * will be extended in the future with new message types, just ignore
562             * any message types you're not interested in, or that you don't
563             * recognize.
564             */
565            if (GoogleCloudMessaging.
566                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
567                sendNotification("Send error: " + extras.toString());
568            } else if (GoogleCloudMessaging.
569                    MESSAGE_TYPE_DELETED.equals(messageType)) {
570                sendNotification("Deleted messages on server: " +
571                        extras.toString());
572            // If it's a regular GCM message, do some work.
573            } else if (GoogleCloudMessaging.
574                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {
575                // This loop represents the service doing some work.
576                for (int i=0; i<5; i++) {
577                    Log.i(TAG, "Working... " + (i+1)
578                            + "/5 @ " + SystemClock.elapsedRealtime());
579                    try {
580                        Thread.sleep(5000);
581                    } catch (InterruptedException e) {
582                    }
583                }
584                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
585                // Post notification of received message.
586                sendNotification("Received: " + extras.toString());
587                Log.i(TAG, "Received: " + extras.toString());
588            }
589        }
590        // Release the wake lock provided by the WakefulBroadcastReceiver.
591        GcmBroadcastReceiver.completeWakefulIntent(intent);
592    }
593
594    // Put the message into a notification and post it.
595    // This is just one simple example of what you might choose to do with
596    // a GCM message.
597    private void sendNotification(String msg) {
598        mNotificationManager = (NotificationManager)
599                this.getSystemService(Context.NOTIFICATION_SERVICE);
600
601        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
602                new Intent(this, DemoActivity.class), 0);
603
604        NotificationCompat.Builder mBuilder =
605                new NotificationCompat.Builder(this)
606        .setSmallIcon(R.drawable.ic_stat_gcm)
607        .setContentTitle("GCM Notification")
608        .setStyle(new NotificationCompat.BigTextStyle()
609        .bigText(msg))
610        .setContentText(msg);
611
612        mBuilder.setContentIntent(contentIntent);
613        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
614    }
615}</pre>
616
617
618<h3 id="sample-send">Send an upstream message</h3>
619<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
620upstream message using the
621<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
622{@code GoogleCloudMessaging}</a> API. In order to receive the upstream message,
623your server should be connected to CCS. You can use one of the demo servers in
624<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
625to CCS.</p>
626
627<pre>public void onClick(final View view) {
628    if (view == findViewById(R.id.send)) {
629        new AsyncTask<Void, Void, String>() {
630            &#64;Override
631            protected String doInBackground(Void... params) {
632                String msg = "";
633                try {
634                    Bundle data = new Bundle();
635                        data.putString("my_message", "Hello World");
636                        data.putString("my_action",
637                                "com.google.android.gcm.demo.app.ECHO_NOW");
638                        String id = Integer.toString(msgId.incrementAndGet());
639                        gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
640                        msg = "Sent message";
641                } catch (IOException ex) {
642                    msg = "Error :" + ex.getMessage();
643                }
644                return msg;
645            }
646
647            &#64;Override
648            protected void onPostExecute(String msg) {
649                mDisplay.append(msg + "\n");
650            }
651        }.execute(null, null, null);
652    } else if (view == findViewById(R.id.clear)) {
653        mDisplay.setText("");
654    }
655}</pre>
656
657<h2 id="run">Running the Sample</h2>
658
659<p>To run the sample:</p>
660
661<ol>
662  <li>Follow the instructions in <a href="gs.html">Getting Started</a> to get your sender ID and
663  API key.</li>
664  <li>Implement your client app, as described in this document. You can find the complete source
665  code for the client app at the <a href="http://code.google.com/p/gcm">open source site</a>.</li>
666  <li>Run one of the demo servers (Java or Python) provided in
667<a href="ccs.html#implement">Implementing an XMPP-based App Server</a>. Whichever demo server you
668 choose, don't forget to edit its code before running it to supply
669your sender ID and API key.
670</li>
671
672</ol>
673
674<h2 id="stats">Viewing Statistics</h2>
675
676<p>To view  statistics and any error messages for your GCM applications:</p>
677<ol>
678  <li> Go to the <a href="http://play.google.com/apps/publish">Developer Console</a>.</li>
679  <li>Login with your developer account.
680  <p>You will see a page that has a list of all of your apps.</p></li>
681  <li> Click on the &quot;statistics&quot; link next to the app for which you
682want to view GCM stats.
683  <p>Now you are on the statistics page.</p> </li>
684  <li>Go to the drop-down menu and select the GCM metric you want to view.
685  </li>
686</ol>
687<p class="note"><strong>Note:</strong> Stats on the Google API Console are not
688enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>
689
690