am 57394e3d: am 2fbe1094: am 3ef445a8: am 68291f33: am db3158ea: Merge "Doc update: Refactoring to client/server." into jb-mr1.1-docs
* commit '57394e3daff094c28ee2a2fb886e1764a1b7728d':
Doc update: Refactoring to client/server.
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index ffe15c5..0cadbd2 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -23,7 +23,7 @@
<li><a href="#msg_examples">Message Examples</a></li>
</ol>
</li>
- <li><a href="#flow">Control Flow</a> </li>
+ <li><a href="#flow">Flow Control</a> </li>
</ol>
<h2>See Also</h2>
@@ -48,6 +48,8 @@
<p>The upstream messaging (device-to-cloud) feature of CCS is part of the Google Play services platform. Upstream messaging is available through the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. To use upstream messaging and the new streamlined registration process, you must <a href="{@docRoot}google/play-services/setup.html">set up</a> the Google Play services SDK.</p>
+<p class="note"><strong>Note:</strong> For an example of an XMPP server, see <a href="server.html#xmpp">GCM Server</a>.
+
<h2 id="gcm">CCS vs. GCM HTTP</h2>
<p>CCS messaging differs from GCM HTTP messaging in the following ways:</p>
@@ -229,69 +231,13 @@
</gcm>
</message></pre>
-<h4 id="python">Python Example</h4>
-<p>This example illustrates how to connect,
-send, and receive GCM messages using XMPP. It shouldn't be used as-is
-on a production deployment.</p>
-<pre>
-import sys, json, xmpp
-SERVER = ('gcm.googleapis.com', 5235)
-#USERNAME = '<your_numeric_project_id>'
-#PASSWORD = '<your_gcm_api_key>'
+<h2 id="flow">Flow Control</h2>
-# Unique message id for downstream messages
-sent_message_id = 0
+<p>Every message sent to CCS receives either an ACK or a NACK response. Messages that haven't received one of these responses are considered pending. If the pending message count reaches 1000, the 3rd-party server should stop sending new messages and wait for CCS to acknowledge some of the existing pending messages.</p>
-def message_callback(session, message):
- global sent_message_id
- gcm = message.getTags('gcm')
+<p>Conversely, to avoid overloading the 3rd-party server, CCS will stop sending if there are too many unacknowledged messages. Therefore, the 3rd-party server should "ACK" received messages as soon as possible to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party server should continue sending ACKs to avoid blocking delivery of new messages.</p>
- if gcm:
- gcm_json = gcm[0].getData()
- msg = json.loads(gcm_json)
- msg_id = msg['message_id']
- device_reg_id = msg['from']
-
- # Ignore non-standard messages (e.g. acks/nacks).
- if not msg.has_key('message_type'):
- # Acknowledge the incoming message.
- send({'to': device_reg_id,
- 'message_type': 'ack',
- 'message_id': msg_id})
-
- # Send a response back to the server.
- send({'to': device_reg_id,
- 'message_id' : str(sent_message_id),
- 'data': {'pong': 1}})
- sent_message_id = sent_message_id + 1
-
-def send(json_dict):
- template = ("<message from='{0}' to='gcm@google.com'>"
- "<gcm xmlns='google:mobile:data'>{1}</gcm></message>")
- client.send(xmpp.protocol.Message(
- node=template.format(client.Bind.bound[0],
- json.dumps(json_dict))))
-
-client = xmpp.Client(SERVER[0], debug=['socket'])
-client.connect(server=SERVER, secure=1, use_srv=False)
-auth = client.auth(USERNAME, PASSWORD, 'test')
-if not auth:
- print 'Authentication failed!'
- sys.exit(1)
-
-client.RegisterHandler('message', message_callback)
-
-while True:
- client.Process(1)</pre>
-
-<h2 id="flow">Control Flow</h2>
-
-<p>Every message sent by a 3rd-party server to CCS receives either an ACK or a NACK response. A single connection can have at most 1000 messages that were sent without having yet received a response.</p>
-
-<p>To enforce this policy, the app can maintain a counter of sent messages that increments on each send and decrements on each ACK or NACK. If the counter exceeds 1000, the app should stop sending messages until an ACK or NACK is received.</p>
-
-<p>Conversely, when CCS sends messages to a 3rd-party server, it expects ACKs for each message it sends, and it will not send more than 1000 unacknowledged messages.</p>
-
-<p>The ACKs and messages must match on each connection. You can only send an ACK for a message on the connection on which it was received.</p>
+<p>ACKs are only valid within the context of one connection. If the connection is closed before a message can be ACKed, the 3rd-party server should wait for CCS to resend the message before ACKing it again.
+</p>
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
new file mode 100644
index 0000000..7604932
--- /dev/null
+++ b/docs/html/google/gcm/client.jd
@@ -0,0 +1,24 @@
+page.title=GCM Client
+page.tags="cloud","push","messaging"
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>See Also</h2>
+
+<ol class="toc">
+<li><a href="gs.html">Getting Started</a></li>
+<li><a href="server.html">GCM Server</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>A GCM client is a GCM-enabled app that runs on an Android device. To write your client code, we recommend that you use the new <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. The client helper library that was offered in previous versions of GCM still works, but it has been superseded by the more efficient <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs.</p>
+
+<p>A full GCM implementation requires both a client implementation and a server-side implementation. For a step-by-step guide to creating a complete sample implementation that includes both client and server, see <a href="gs.html">Getting Started</a>. </p>
+
+<p>
+
+
diff --git a/docs/html/google/gcm/demo.jd b/docs/html/google/gcm/demo.jd
index 6da9e98..012eb9a 100644
--- a/docs/html/google/gcm/demo.jd
+++ b/docs/html/google/gcm/demo.jd
@@ -1,6 +1,22 @@
page.title=GCM Demo Application
@jd:body
+<div id="deprecatedSticker">
+ <a href="#"
+ onclick="$('#naMessage').show();$('#deprecatedSticker').hide();return false">
+ <strong>This doc is deprecated</strong></a>
+</div>
+
+
+<div id="naMessage" style="display:block">
+<div><p><strong>The information in this document has been superseded by <a href="server.html">GCM Server</a> and <a href="client.html">GCM Client</a></strong>. Please use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> API instead of the GCM client helper library. The GCM server helper library is still valid.</p>
+
+ <input style="margin-top:1em;padding:5px" type="button"
+ value="That's nice, but I still want to read this document"
+onclick="$('#naMessage').hide();$('#deprecatedSticker').show()" />
+</div>
+</div>
+
<div id="qv-wrapper">
<div id="qv">
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index 5acf60d..ceb82b0 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -28,20 +28,6 @@
<li><a href="#user">What Does the User See?</a></li>
</ol>
</li>
- <li><a href="#writing_apps">Writing Android Applications that use GCM</a>
- <ol>
- <li><a href="#manifest">Creating the Manifest</a></li>
- <li><a href="#registering">Registering for GCM</a></li>
-
- <li><a href="#handling_intents">Handling Intents Sent by GCM</a>
- <ol>
- <li><a href="#handling_reg">Handling Registration Results</a></li>
- <li><a href="#received_data">Handling Received Data</a></li>
- </ol>
- </li>
- <li><a href="#testing">Developing and Testing Your Android Applications</a></li>
- </ol>
- </li>
<li><a href="#server">Role of the 3rd-party Application Server</a>
<ol class="toc">
<li><a href="#send-msg">Sending Messages</a>
@@ -53,7 +39,6 @@
</ol>
<li><a href="#stats">Viewing Statistics</a>
</li>
- <li><a href="#example">Examples</a></li>
</ol>
@@ -306,336 +291,6 @@
includes GCM. They must approve the use of this feature to install the
Android application. </p>
-<h2 id="writing_apps">Writing Android Applications that Use GCM</h2>
-
-<p>To write Android applications that use GCM, you must have an application
-server that can perform the tasks described in <a href="#server">Role of the
-3rd-party Application Server</a>. This section describes the steps you take to
-create a client application that uses GCM.</p>
-
-<p>Remember that there is no user interface associated with GCM.
-However you choose to process messages in your Android application is up to you.</p>
-
-<p>There are two primary steps involved in writing a client Android application:</p>
-
-<ul>
- <li>Creating a manifest that contains the permissions the Android application needs to
-use GCM.</li>
- <li>Implementing your code. To use GCM, this implementation must
-include:
- <ul>
- <li>Code to start and stop the registration service.</li>
- <li>Receivers for the <code>com.google.android.c2dm.intent.RECEIVE</code> and <code>com.google.android.c2dm.intent.REGISTRATION</code> intents.</li>
- </ul>
- </li>
-</ul>
-
-<p class="note"><strong>Note:</strong> This section describes how to
-write an app without using the
-<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>.
-For details on writing
-an app that uses the helper libraries (which is the recommended and
-simpler approach), see <a href="gs.html">GCM: Getting Started</a>.
-
-<h3 id="manifest">Creating the Manifest</h3>
-
-<p>To use the GCM feature, the
-<code>AndroidManifest.xml</code> file must include the following:</p>
-
-<ul>
- <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so the Android application can register and receive messages.</li>
- <li>The <code>android.permission.INTERNET</code> permission so the Android application can send the registration ID to the 3rd-party server.</li>
- <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4)</li>
- <li>The <code>android.permission.WAKE_LOCK</code> permission so the application can keep the processor from sleeping when a message is received. Optional—use only if the app wants to keep the device from sleeping.</li>
- <li>An <code>applicationPackage + ".permission.C2D_MESSAGE</code> permission to prevent other Android applications from registering and receiving the Android application's
-messages. The permission name must exactly match this pattern—otherwise the Android application will not receive the messages.</li>
- <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code> and <code>com.google.android.c2dm.intent.REGISTRATION</code>, with the category set
-as <code>applicationPackage</code>. The receiver should require the <code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
-Framework can send a message to it. Note that both registration and the receiving
-of messages are implemented as <a href="{@docRoot}guide/components/intents-filters.html">Intents</a>.</li>
- <li>An intent service to handle the intents received by the broadcast receiver. Optional.</li>
- <li>If the GCM feature is critical to the Android application's function, be sure to
-set <code>android:minSdkVersion="8"</code> in the manifest. This
-ensures that the Android application cannot be installed in an environment in which it
-could not run properly. </li>
-</ul>
-
-<p>Here are excerpts from a manifest that supports GCM:</p>
-
-<pre class="prettyprint pretty-xml">
-<manifest package="com.example.gcm" ...>
-
- <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" />
- <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
-
- <permission android:name="com.example.gcm.permission.C2D_MESSAGE"
- android:protectionLevel="signature" />
- <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
-
- <application ...>
- <receiver
- android:name=".MyBroadcastReceiver"
- 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.example.gcm" />
- </intent-filter>
- </receiver>
- <service android:name=".MyIntentService" />
- </application>
-
-</manifest>
-</pre>
-
-<h3 id="registering">Registering for GCM</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
- <h2>Streamlined Registration</h2>
- <p>There is now a simpler alternative to registering and unregistering. Simply call the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> method
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register">{@code register(senderID...)}</a>.
-This method registers the application for GCM and returns the registration ID. To unregister, call the
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#unregister">{@code unregister()}</a> method (though you should rarely if ever need to unregister).</p>
-</div>
-</div>
-
-<p>An Android application needs to register with GCM servers before it can receive messages. To register, the application sends an Intent
-(<code>com.google.android.c2dm.intent.REGISTER</code>), with 2 extra parameters:
-</p>
-
-<ul>
- <li><code>sender</code> is the project number of the account authorized to send messages
-to the Android application. </li>
- <li><code>app</code> is the Android application's ID, set with a <code>PendingIntent</code> to
-allow the registration service to extract Android application information. </li>
-</ul>
-
-<p>For example:</p>
-
-<pre style="clear:right">Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
-// sets the app name in the intent
-registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
-registrationIntent.putExtra("sender", senderID);
-startService(registrationIntent);</pre>
-
-<p>This intent will be asynchronously sent to the GCM server, and the response will be delivered to
-the application as a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent containing
-the registration ID assigned to the Android application running on that particular device.</p>
-
-<p>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.</p>
-
-<h3 id="unregistering">Unregistering from GCM</h3>
-
-<p>To unregister from GCM, do the following:</p>
-
-<pre class="prettyprint pretty-java">Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
-unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
-startService(unregIntent);
-</pre>
-
-<p>Similar to the registration request, this intent is sent asynchronously, and the response comes as a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent.
-
-
-<h3 id="handling_intents">Handling Intents sent by GCM</h3>
-
-<p>As discussed in <a href="#manifest">Creating the Manifest</a>, the manifest
-defines a broadcast receiver for the <code>com.google.android.c2dm.intent.REGISTRATION</code> and <code>com.google.android.c2dm.intent.RECEIVE</code> intents.
-These <a href="{@docRoot}guide/components/intents-filters.html">intents</a> are sent by GCM to indicate that a device was registered (or unregistered), or to deliver messages, respectively.</p>
-
-<p>Handling these intents might require I/O operations (such as network calls to the 3rd-party server), and
-such operations should not be done in the receiver's <code>onReceive()</code> method.
-You may be tempted to spawn a new thread directly, but there are no guarantees that the process will run long enough for the thread to finish the work.
-Thus the recommended way to handle the intents is to delegate them to a service, such as an {@link android.app.IntentService}.
-For example:</p>
-
-
-<pre class="prettyprint pretty-java">
-public class MyBroadcastReceiver extends BroadcastReceiver {
-
- @Override
- public final void onReceive(Context context, Intent intent) {
- MyIntentService.runIntentInService(context, intent);
- setResult(Activity.RESULT_OK, null, null);
- }
-}
-</pre>
-
-<p>Then in <code>MyIntentService</code>:</p>
-<pre class="prettyprint pretty-java">
-public class MyIntentService extends IntentService {
-
- private static PowerManager.WakeLock sWakeLock;
- private static final Object LOCK = MyIntentService.class;
-
- static void runIntentInService(Context context, Intent intent) {
- synchronized(LOCK) {
- if (sWakeLock == null) {
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "my_wakelock");
- }
- }
- sWakeLock.acquire();
- intent.setClassName(context, MyIntentService.class.getName());
- context.startService(intent);
- }
-
- @Override
- public final void onHandleIntent(Intent intent) {
- try {
- String action = intent.getAction();
- if (action.equals("com.google.android.c2dm.intent.REGISTRATION")) {
- handleRegistration(intent);
- } else if (action.equals("com.google.android.c2dm.intent.RECEIVE")) {
- handleMessage(intent);
- }
- } finally {
- synchronized(LOCK) {
- sWakeLock.release();
- }
- }
- }
-}
-</pre>
-
-<p class="note"><strong>Note:</strong> your application must acquire a wake lock before starting the service—otherwise the device could be put to sleep before the service is started.</p>
-
-<h4 id="handling_reg">Handling Registration Results</h4>
-
-<p>When a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent is received, it could potentially contain 3 extras: <code>registration_id</code>, <code>error</code>, and <code>unregistered</code>.
-
-<p>When a registration succeeds, <code>registration_id</code> contains the registration ID and the other extras are not set.
-The application must ensure that the 3rd-party server receives the registration ID. It may do so by saving the registration ID and sending it to the server.
-If the network is down or there are errors, the application should retry sending the registration ID when the network is up again or the next time it starts.</p>
-
-<p class="note"><strong>Note:</strong> Although the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent is typically received after a request was made by the application,
-Google may periodically refresh the registration ID. So the application must be prepared to handle it at any time.</p>
-
-<p>When an unregistration succeeds, only the <code>unregistered</code> extra is set, and similar to the registration workflow,
-the application must contact the 3rd-party server to remove the registration ID (note that the registration ID is not available in the intent,
-but the application should have saved the registration ID when it got it).<p>
-
-<p>If the application request (be it register or unregister) fails, the <code>error</code> will be set with an error code, and the other extras will not be set.
-
-Here are the possible error codes:</p>
-
-<table>
- <tr>
- <th>Error Code</th>
- <th>Description</th>
- </tr>
- <tr>
- <td><code>SERVICE_NOT_AVAILABLE</code></td>
- <td>The device can't read the response, or there was a 500/503 from the
-server that can be retried later. The Android application should use exponential back-off and retry. See <a href="adv.html#retry">Advanced Topics</a> for more information. </td>
- </tr>
- <tr>
- <td><code>ACCOUNT_MISSING</code></td>
- <td>There is no Google account on the phone. The Android application should ask the
-user to open the account manager and add a Google account. Fix on the device
-side.</td>
- </tr>
- <tr>
- <td><code>AUTHENTICATION_FAILED</code></td>
- <td>Bad Google Account password. The Android application should ask the user to enter his/her Google Account
-password, and let the user retry manually later. Fix on the device side.</td>
- </tr>
- <tr>
- <td><code>INVALID_SENDER</code></td>
- <td>The sender account is not recognized. This must be fixed on the Android application side. The developer must fix the application to provide the right <code>sender</code> extra in the <code>com.google.android.c2dm.intent.REGISTER</code> intent.</td>
- </tr>
- <tr>
- <td><code>PHONE_REGISTRATION_ERROR</code></td>
- <td> Incorrect phone registration with Google. This
-phone doesn't currently support GCM.</td>
- </tr>
- <tr>
- <td><code>INVALID_PARAMETERS</code></td>
- <td>The request sent by the phone does not contain the expected parameters. This phone doesn't currently support GCM.</td>
- </tr>
-</table>
-
-
-
-
-<p>Here's an example on how to handle the registration in the <code>MyIntentService</code> example:</p>
-
-<pre class="prettyprint pretty-java">
-private void handleRegistration(Intent intent) {
- String registrationId = intent.getStringExtra("registration_id");
- String error = intent.getStringExtra("error");
- String unregistered = intent.getStringExtra("unregistered");
- // registration succeeded
- if (registrationId != null) {
- // store registration ID on shared preferences
- // notify 3rd-party server about the registered ID
- }
-
- // unregistration succeeded
- if (unregistered != null) {
- // get old registration ID from shared preferences
- // notify 3rd-party server about the unregistered ID
- }
-
- // last operation (registration or unregistration) returned an error;
- if (error != null) {
- if ("SERVICE_NOT_AVAILABLE".equals(error)) {
- // optionally retry using exponential back-off
- // (see <a href="adv.html#retry">Advanced Topics</a>)
- } else {
- // Unrecoverable error, log it
- Log.i(TAG, "Received error: " + error);
- }
- }
-}</pre>
-
-
-
-<h4 id="received_data">Handling Received Data</h4>
-
-<p>The <code>com.google.android.c2dm.intent.RECEIVE</code> intent is used by GCM to
-deliver the messages sent by the 3rd-party server to the application running in the device.
-If the server included key-pair values in the <code>data</code> parameter, they are available as
-extras in this intent, with the keys being the extra names. GCM also includes an extra called
-<code>from</code> which contains the sender ID as an string, and another called <code>collapse_key</code> containing the collapse key (when in use).
-
-<p>Here is an example, again using the <code>MyIntentReceiver</code> class:</p>
-
-<pre class="prettyprint pretty-java">
-private void handleMessage(Intent intent) {
- // server sent 2 key-value pairs, score and time
- String score = intent.getExtra("score");
- String time = intent.getExtra("time");
- // generates a system notification to display the score and time
-}</pre>
-
-<h3 id="testing">Developing and Testing Your Android Applications</h3>
-
-<p>Here are some guidelines for developing and testing an Android application
-that uses the GCM feature:</p>
-
-<ul>
- <li>To develop and test your Android applications, you need to run and debug the
-applications on an Android 2.2 system image that includes the necessary
-underlying Google services. </li>
- <li>To develop and debug on an actual device, you need a device running an
-Android 2.2 system image that includes the Google Play Store application. </li>
- <li>To develop and test on the Android Emulator, you need to download the
-Android 2.2 version of the Google APIs Add-On into your SDK using the <em>Android
-SDK and AVD Manager</em>. Specifically, you need to download the component named
-"Google APIs by Google Inc, Android API 8". Then, you need to set up
-an AVD that uses that system image. </li>
- <li>If the GCM feature is critical to the Android application's function, be sure to
-set <code>android:minSdkVersion="8"</code> in the manifest. This
-ensures that the Android application cannot be installed in an environment in which it
-could not run properly. </li>
-</ul>
-
<h2 id="server">Role of the 3rd-party Application Server</h2>
@@ -1105,6 +760,4 @@
</ol>
<p class="note"><strong>Note:</strong> Stats on the Google API Console are not enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>
-<h2 id="example">Examples</h2>
-<p>See the <a href="demo.html">GCM Demo Application</a> document.</p>
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index d938bd6..8ceea0cc 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -12,14 +12,14 @@
<li><a href="#create-proj">Creating a Google API Project</a></li>
<li><a href="#gcm-service">Enabling the GCM Service</a></li>
<li><a href="#access-key">Obtaining an API Key</a></li>
-<li><a href="#android-app">Writing the Android Application</a>
+<li><a href="#client">Writing a Client App</a></li>
+<li><a href="#server">Writing the Server Code</a></li>
</ol>
<h2>See Also</h2>
<ol class="toc">
<li><a href="https://code.google.com/apis/console">Google APIs Console page</a></li>
-<li><a href="{@docRoot}google/gcm/helper.html">Using the GCM Helper Libraries</a></li>
<li><a href="https://services.google.com/fb/forms/gcm/" class="external-link" target="_android">CCS and User Notifications Signup Form</a></li>
</ol>
@@ -29,20 +29,9 @@
<p>The sections below guide you through the process of setting up a GCM
implementation.
Before you start, make sure to <a href="/google/play-services/setup.html">set up
-the Google Play Services SDK</a>. You need this SDK to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> methods. Strictly speaking, the only thing you absolutely need this API for is upstream (device-to-cloud) messaging, but it also offers a streamlined registration API that is recommended.</p>
+the Google Play Services SDK</a>. You need this SDK to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> methods.</p>
-
-<!--the basic steps are:
-
-<ul>
-<li>Creating a Google APIs Project</li>
-<li>Setting up GCM in your apps</li>
-<li>Integrating </li>
-
-<p>Note that a full GCM implementation requires a server-side implementation, in addition to the client implementation in your app. For complete information, make sure to read the <a href="/google/gcm/index.html">Google Cloud Messaging documentation</a>.
--->
-
-
+<p>Note that a full GCM implementation requires a server-side implementation, in addition to the client implementation in your app. This document offers a complete example that includes both the client and server.</p>
<h2 id="create-proj">Creating a Google API project</h2>
@@ -95,17 +84,21 @@
<p> Take note of the <strong>API key</strong> value (<code>YourKeyWillBeShownHere</code>) in this example, as it will be used later on.</p>
<p class="note"><strong>Note:</strong> If you need to rotate the key, click <strong>Generate new key</strong>. A new key will be created while the old one will still be active for up to 24 hours. If you want to get rid of the old key immediately (for example, if you feel it was compromised), click <strong>Delete key</strong>.</p>
+<p>The following sections walk you through the steps of creating client and server-side code.</p>
-<h2 id="android-app">Writing the Android Application</h2>
-<p>This section describes the steps involved in writing an Android application that uses GCM.</p>
+<h2 id="client">Writing a Client App</h2>
-<h4 id="manifest">Step 1: Make the following changes in the application's Android manifest</h4>
+<p>This section walks you through the steps involved in writing a client-side application—that is, the GCM-enabled application that runs on an Android device. This client sample is designed to work in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>, below.</p>
+
+
+
+<h3 id="manifest">Step 1: Edit Your App's Manifest</h3>
<ul>
<li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so the Android application can register and receive messages.</li>
<li>The <code>android.permission.INTERNET</code> permission so the Android application can send the registration ID to the 3rd party server.</li>
<li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4)</li>
<li>The <code>android.permission.WAKE_LOCK</code> permission so the application can keep the processor from sleeping when a message is received. Optional—use only if the app wants to keep the device from sleeping.</li>
- <li>An <code>applicationPackage + ".permission.C2D_MESSAGE</code> permission to prevent other Android applications from registering and receiving the Android application's
+ <li>An <code>applicationPackage + ".permission.C2D_MESSAGE"</code> permission to prevent other Android applications from registering and receiving the Android application's
messages. The permission name must exactly match this pattern—otherwise the Android application will not receive the messages.</li>
<li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with the category set
as <code>applicationPackage</code>. The receiver should require the <code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
@@ -149,106 +142,199 @@
</pre>
-<h4>Step 2: Register for GCM</h4>
+<h3 id="register">Step 2: Register for GCM</h3>
<p>An Android application running on a mobile device registers to receive messages by calling
the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> method
<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register">{@code register(senderID...)}</a>.
This method registers the application for GCM and returns the registration ID. This streamlined approach replaces the previous
-GCM registration process.</p>
+GCM registration process. See the example below for details.</p>
-<h4> Step 3: Write your application</h4>
+<h3 id="app"> Step 3: Write Your Application</h3>
<p>Finally, write your application. GCM offers a variety of ways to get the job done:</p>
<ul>
- <li>For your messaging server, you can either use the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), the older <a href="gcm.html">GCM HTTP server</a>, or both in tandem.</li>
- <li>To write your client application, you can use any of the following:
- <ul>
- <li>The helper libraries, which are described in the <a href="{@docRoot}google/gcm/demo.html">Demo App Tutorial</a> and <a href="{@docRoot}google/gcm/helper.html">Using the GCM Helper Libraries</a>.</li>
- <li>The approach described in the <a href="{@docRoot}google/gcm/gcm.html#writing_apps">GCM Architectural Overview</a>.</li>
- <li>Regardless, you must use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs if you are doing upstream (device-to-cloud) messaging. Even if you are not doing upstream messaging, we recommend that you use this API to take advantage of the streamlined registration process—described above and shown in the following sample.</li>
+ <li>For your messaging server, you can either use the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), the older <a href="gcm.html">GCM HTTP server</a>, or both in tandem. For more discussion, see see <a href="server.html">GCM Server</a>.</li>
+ <li>To write your client application (that is, the GCM-enabled app that runs on an Android device), use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs as shown below. Don't forget to set up your project to use the Google Play services SDK as described in <a href="/google/play-services/setup.html">Setup Google Play Services SDK</a>.</li>
</ul>
</li>
</ul>
-<h5 id="gs_example">Example</h5>
+<h4 id="example">Example</h4>
-<p>Here is a sample application that illustrates how to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. In this example, the sender is a <a href="{@docRoot}google/gcm/ccs.html">CCS</a> echo server. The sample consists of a main Activity ({@code DemoActivity}) and a broadcast receiver ({@code GcmBroadcastReceiver}).</p>
+<p>Here is a sample client application that illustrates how to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. The sample consists of a main activity ({@code DemoActivity}) and a broadcast receiver ({@code GcmBroadcastReceiver}). You can use this client sample code in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>.</p>
+<p>Note the following:</p>
+
+<ul>
+ <li>The sample primarily illustrates two things: registration, and upstream messaging. Upstream messaging only applies to apps that are running against a <a href="ccs.html">CCS</a> server; HTTP-based servers don't support upstream messaging.</li>
+ <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> registration APIs replace the old registration process, which was based on the now-obsolete client helper library. While the old registration process still works, we encourage you to use the newer <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> registration APIs, regardless of your underlying server.</li>
+</ul>
+
+<h5>Registering</h5>
<p>An Android application needs to register with GCM servers before it can receive messages. So in its {@code onCreate()} method, {@code DemoActivity} checks to see whether the app is registered with GCM and with the server:</p>
-<pre>public class DemoActivity extends Activity {
+<pre>/**
+ * Main UI for the demo app.
+ */
+public class DemoActivity extends Activity {
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
+ private static final String PROPERTY_APP_VERSION = "appVersion";
+ private static final String PROPERTY_ON_SERVER_EXPIRATION_TIME =
+ "onServerExpirationTimeMs";
/**
- * You can use your own project ID instead. This sender is a test CCS
- * echo server.
+ * Default lifespan (7 days) of a reservation until it is considered expired.
*/
- String GCM_SENDER_ID = "Your-Sender-ID";
+ public static final long REGISTRATION_EXPIRY_TIME_MS = 1000 * 3600 * 24 * 7;
- // Tag for log messages.
+ /**
+ * Substitute you own sender ID here.
+ */
+ String SENDER_ID = "Your-Sender-ID";
+
+ /**
+ * Tag used on log messages.
+ */
static final String TAG = "GCMDemo";
TextView mDisplay;
GoogleCloudMessaging gcm;
AtomicInteger msgId = new AtomicInteger();
SharedPreferences prefs;
+ Context context;
+
String regid;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // Make sure the app is registered with GCM and with the server
- prefs = getSharedPreferences(DemoActivity.class.getSimpleName(),
- Context.MODE_PRIVATE);
setContentView(R.layout.main);
-
mDisplay = (TextView) findViewById(R.id.display);
- regid = prefs.getString(PROPERTY_REG_ID, null);
-
- // If there is no registration ID, the app isn't registered.
- // Call registerBackground() to register it.
- if (regid == null) {
+ context = getApplicationContext();
+ regid = getRegistrationId(context);
+
+ if (regid.length() == 0) {
registerBackground();
}
-
gcm = GoogleCloudMessaging.getInstance(this);
- }</pre>
+ }
+...
+}</pre>
-<p>If the app isn't registered, {@code DemoActivity} calls the following {@code registerBackground()} method to register it. Note that because GCM methods are blocking, this has to take place on a background thread. This sample uses {@link android.os.AsyncTask} to accomplish this:</p>
+<p>The app calls {@code getRegistrationId()} to see whether there is an existing registration ID stored in shared preferences:</p>
-<pre>private void registerBackground() {
+<pre>/**
+ * Gets the current registration id for application on GCM service.
+ * <p>
+ * If result is empty, the registration has failed.
+ *
+ * @return registration id, or empty string if the registration is not
+ * complete.
+ */
+private String getRegistrationId(Context context) {
+ final SharedPreferences prefs = getGCMPreferences(context);
+ String registrationId = prefs.getString(PROPERTY_REG_ID, "");
+ if (registrationId.length() == 0) {
+ Log.v(TAG, "Registration not found.");
+ return "";
+ }
+ // check if app was updated; if so, it must clear registration id to
+ // avoid a race condition if GCM sends a message
+ int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
+ int currentVersion = getAppVersion(context);
+ if (registeredVersion != currentVersion || isRegistrationExpired()) {
+ Log.v(TAG, "App version changed or registration expired.");
+ return "";
+ }
+ return registrationId;
+}
+
+...
+
+/**
+ * @return Application's {@code SharedPreferences}.
+ */
+private SharedPreferences getGCMPreferences(Context context) {
+ return getSharedPreferences(DemoActivity.class.getSimpleName(),
+ Context.MODE_PRIVATE);
+}</pre>
+
+<p>If the registration ID doesn't exist, or the app was updated, or the registration ID has expired, {@code getRegistrationId()} returns an empty string to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls the following methods to check the app version and whether the regID has expired:</p>
+
+<pre>/**
+ * @return Application's version code from the {@code PackageManager}.
+ */
+private static int getAppVersion(Context context) {
+ try {
+ PackageInfo packageInfo = context.getPackageManager()
+ .getPackageInfo(context.getPackageName(), 0);
+ return packageInfo.versionCode;
+ } catch (NameNotFoundException e) {
+ // should never happen
+ throw new RuntimeException("Could not get package name: " + e);
+ }
+}
+
+/**
+ * Checks if the registration has expired.
+ *
+ * <p>To avoid the scenario where the device sends the registration to the
+ * server but the server loses it, the app developer may choose to re-register
+ * after REGISTRATION_EXPIRY_TIME_MS.
+ *
+ * @return true if the registration has expired.
+ */
+private boolean isRegistrationExpired() {
+ final SharedPreferences prefs = getGCMPreferences(context);
+ // checks if the information is not stale
+ long expirationTime =
+ prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
+ return System.currentTimeMillis() > expirationTime;
+}</pre>
+
+
+<p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the following {@code registerBackground()} method to register. Note that because GCM methods are blocking, this has to take place on a background thread. This sample uses {@link android.os.AsyncTask} to accomplish this:</p>
+
+<pre>
+/**
+ * Registers the application with GCM servers asynchronously.
+ * <p>
+ * Stores the registration id, app versionCode, and expiration time in the
+ * application's shared preferences.
+ */
+private void registerBackground() {
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
String msg = "";
try {
- regid = gcm.register(GCM_SENDER_ID);
+ if (gcm == null) {
+ gcm = GoogleCloudMessaging.getInstance(context);
+ }
+ regid = gcm.register(SENDER_ID);
msg = "Device registered, registration id=" + regid;
- // You should send the registration ID to your server over HTTP,
+ // You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
- // For this demo: we don't need to send it because the device
- // will send upstream messages to a server that will echo back
- // the message using the 'from' address in the message.
-
- // Save the regid for future use - no need to register again.
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(PROPERTY_REG_ID, regid);
- editor.commit();
+ // For this demo: we don't need to send it because the device
+ // will send upstream messages to a server that echo back the message
+ // using the 'from' address in the message.
+
+ // Save the regid - no need to register again.
+ setRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
- // Once registration is done, display the registration status
- // string in the Activity's UI.
+
@Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
@@ -256,7 +342,33 @@
}.execute(null, null, null);
}</pre>
-<p>When the user clicks the app's <strong>Echo</strong> button, the app generates the necessary XMPP stanza for the message, which it sends to the echo server:</p>
+<p>After registering, the app calls {@code setRegistrationId()} to store the registration ID in shared preferences for future use:</p>
+
+<pre>/**
+ * Stores the registration id, app versionCode, and expiration time in the
+ * application's {@code SharedPreferences}.
+ *
+ * @param context application's context.
+ * @param regId registration id
+ */
+private void setRegistrationId(Context context, String regId) {
+ final SharedPreferences prefs = getGCMPreferences(context);
+ int appVersion = getAppVersion(context);
+ Log.v(TAG, "Saving regId on app version " + appVersion);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(PROPERTY_REG_ID, regId);
+ editor.putInt(PROPERTY_APP_VERSION, appVersion);
+ long expirationTime = System.currentTimeMillis() + REGISTRATION_EXPIRY_TIME_MS;
+
+ Log.v(TAG, "Setting registration expiry time to " +
+ new Timestamp(expirationTime));
+ editor.putLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, expirationTime);
+ editor.commit();
+}</pre>
+
+<h5>Sending a message</h5>
+<p>When the user clicks the app's <strong>Send</strong> button, the app sends an upstream message using the new <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. In order to receive the upstream message, your server should be connected to CCS. You can use the code shown in <a href="#server">Writing the Server Code</a> as a sample XMPP client to connect to CCS.</p>
+
<pre>public void onClick(final View view) {
if (view == findViewById(R.id.send)) {
new AsyncTask<Void, Void, String>() {
@@ -265,11 +377,10 @@
String msg = "";
try {
Bundle data = new Bundle();
- // data is a key-value pair.
- data.putString("hello", "world");
+ data.putString("hello", "World");
String id = Integer.toString(msgId.incrementAndGet());
- gcm.send(GCM_SENDER_ID + "@gcm.googleapis.com", id, data);
- msg = "Sending message";
+ gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
+ msg = "Sent message";
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
@@ -278,23 +389,25 @@
@Override
protected void onPostExecute(String msg) {
- // Displays the text "Sending message"
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
- }
+ } else if (view == findViewById(R.id.clear)) {
+ mDisplay.setText("");
+ }
}</pre>
<p>As described above in <a href="#manifest">Step 1</a>, the app includes a broadcast receiver for the <code>com.google.android.c2dm.intent.RECEIVE</code> intent. This is the mechanism GCM uses to deliver messages. When {@code onClick()} calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()} method, which has the responsibility of handling the GCM message. In this sample the receiver's {@code onReceive()} method calls {@code sendNotification()} to put the message into a notification:</p>
-<pre>public class GcmBroadcastReceiver extends BroadcastReceiver {
+<pre>/**
+ * Handling of GCM messages.
+ */
+public class GcmBroadcastReceiver extends BroadcastReceiver {
static final String TAG = "GCMDemo";
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
Context ctx;
-
-
@Override
public void onReceive(Context context, Intent intent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
@@ -303,7 +416,7 @@
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + intent.getExtras().toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
- sendNotification("Deleted messages on server: " +
+ sendNotification("Deleted messages on server: " +
intent.getExtras().toString());
} else {
sendNotification("Received: " + intent.getExtras().toString());
@@ -313,21 +426,98 @@
// Put the GCM message into a notification and post it.
private void sendNotification(String msg) {
- mNotificationManager = (NotificationManager)
- ctx.getSystemService(Context.NOTIFICATION_SERVICE);
-
- PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
- new Intent(ctx, DemoActivity.class), 0);
-
- NotificationCompat.Builder mBuilder =
- new NotificationCompat.Builder(ctx)
- .setSmallIcon(R.drawable.ic_stat_notification)
- .setContentTitle("GCM Notification")
- .setStyle(new NotificationCompat.BigTextStyle()
- .bigText(msg))
- .setContentText(msg);
-
- mBuilder.setContentIntent(contentIntent);
- mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
+ mNotificationManager = (NotificationManager)
+ ctx.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
+ new Intent(ctx, DemoActivity.class), 0);
+
+ NotificationCompat.Builder mBuilder =
+ new NotificationCompat.Builder(ctx)
+ .setSmallIcon(R.drawable.ic_stat_gcm)
+ .setContentTitle("GCM Notification")
+ .setStyle(new NotificationCompat.BigTextStyle()
+ .bigText(msg))
+ .setContentText(msg);
+
+ mBuilder.setContentIntent(contentIntent);
+ mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}</pre>
+
+<h2 id="server">Writing the Server Code</h2>
+
+<p>Here is an example of a CCS server written in Python. You can use this in conjunction with the sample client code shown above. This sample echo server sends an initial message, and for every upstream message received, it sends a dummy response back to the application that sent the upstream message. This example illustrates how to connect,
+send, and receive GCM messages using XMPP. It shouldn't be used as-is
+on a production deployment. For examples of HTTP-based servers, see <a href="server.html">GCM Server</a>.</p>
+
+<pre>
+#!/usr/bin/python
+import sys, json, xmpp, random, string
+
+SERVER = 'gcm.googleapis.com'
+PORT = 5235
+USERNAME = ''
+PASSWORD = ''
+REGISTRATION_ID = ''
+
+unacked_messages_quota = 1000
+send_queue = []
+
+# Return a random alphanumerical id
+def random_id():
+ rid = ''
+ for x in range(8): rid += random.choice(string.ascii_letters + string.digits)
+ return rid
+
+def message_callback(session, message):
+ global unacked_messages_quota
+ gcm = message.getTags('gcm')
+ if gcm:
+ gcm_json = gcm[0].getData()
+ msg = json.loads(gcm_json)
+ if not msg.has_key('message_type'):
+ # Acknowledge the incoming message immediately.
+ send({'to': msg['from'],
+ 'message_type': 'ack',
+ 'message_id': msg['message_id']})
+ # Queue a response back to the server.
+ if msg.has_key('from'):
+ # Send a dummy echo response back to the app that sent the upstream message.
+ send_queue.append({'to': msg['from'],
+ 'message_id': random_id(),
+ 'data': {'pong': 1}})
+ elif msg['message_type'] == 'ack' or msg['message_type'] == 'nack':
+ unacked_messages_quota += 1
+
+def send(json_dict):
+ template = ("<message><gcm xmlns='google:mobile:data'>{1}</gcm></message>")
+ client.send(xmpp.protocol.Message(
+ node=template.format(client.Bind.bound[0], json.dumps(json_dict))))
+
+def flush_queued_messages():
+ global unacked_messages_quota
+ while len(send_queue) and unacked_messages_quota > 0:
+ send(send_queue.pop(0))
+ unacked_messages_quota -= 1
+
+client = xmpp.Client('gcm.googleapis.com', debug=['socket'])
+client.connect(server=(SERVER,PORT), secure=1, use_srv=False)
+auth = client.auth(USERNAME, PASSWORD)
+if not auth:
+ print 'Authentication failed!'
+ sys.exit(1)
+
+client.RegisterHandler('message', message_callback)
+
+send_queue.append({'to': REGISTRATION_ID,
+ 'message_id': 'reg_id',
+ 'data': {'message_destination': 'RegId',
+ 'message_id': random_id()}})
+
+while True:
+ client.Process(1)
+ flush_queued_messages()</pre>
+
+
+
diff --git a/docs/html/google/gcm/helper.jd b/docs/html/google/gcm/helper.jd
index bde2df0..e7f2f73 100644
--- a/docs/html/google/gcm/helper.jd
+++ b/docs/html/google/gcm/helper.jd
@@ -2,6 +2,23 @@
page.tags="cloud","push","messaging"
@jd:body
+<div id="deprecatedSticker">
+ <a href="#"
+ onclick="$('#naMessage').show();$('#deprecatedSticker').hide();return false">
+ <strong>This doc is deprecated</strong></a>
+</div>
+
+
+<div id="naMessage" style="display:block">
+<div><p><strong>The information in this document has been superseded by <a href="server.html">GCM Server</a> and <a href="client.html">GCM Client</a></strong>. Please use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> API instead of the GCM client helper library. The GCM server helper library is still valid.</p>
+
+ <input style="margin-top:1em;padding:5px" type="button"
+ value="That's nice, but I still want to read this document"
+onclick="$('#naMessage').hide();$('#deprecatedSticker').show()" />
+</div>
+</div>
+
+
<div id="qv-wrapper">
<div id="qv">
diff --git a/docs/html/google/gcm/index.jd b/docs/html/google/gcm/index.jd
index aeba86f..8f325b8 100644
--- a/docs/html/google/gcm/index.jd
+++ b/docs/html/google/gcm/index.jd
@@ -49,6 +49,9 @@
<h4>Seamless multi-device messaging</h4>
<p>Maps a single user to a notification key, which you can then use to send a single message to multiple devices owned by the user. Use <a href="https://services.google.com/fb/forms/gcm/">this form</a> to sign up for User Notifications. <a href="{@docRoot}google/gcm/notifications.html">Learn more »</a></p>
+
+ <h4>Get Started</h4>
+ <p>Get started using the new features with a tutorial that walks you through creating a GCM app. <a href="{@docRoot}google/gcm/gs.html">Learn more »</a></p>
</div>
</div>
diff --git a/docs/html/google/gcm/notifications.jd b/docs/html/google/gcm/notifications.jd
index 6a4b34a..df171cf 100644
--- a/docs/html/google/gcm/notifications.jd
+++ b/docs/html/google/gcm/notifications.jd
@@ -52,6 +52,9 @@
<p>The way this works is that during registration, the 3rd-party server requests a {@code notification_key}. The {@code notification_key} maps a particular user to all of the user's associated registration IDs (a regID represents a particular Android application running on a particular device). Then instead of sending one message to one regID at a time, the 3rd-party server can send a message to to the {@code notification_key}, which then sends the message to all of the user's regIDs.</p>
+<p class="note"><strong>Note:</strong> A notification dismissal message is like any other upstream message, meaning that it will be delivered to the other devices that belong to the specified {@code notification_key}. You should design your app to handle cases where the app receives a dismissal message, but has not yet displayed the notification that is being dismissed. You can solve this by caching the dismissal and then reconciling it with the corresponding notification.
+</p>
+
<p>You can use this feature with either the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), or the older <a href="gcm.html">GCM HTTP server</a>.</p>
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
new file mode 100644
index 0000000..92a1531
--- /dev/null
+++ b/docs/html/google/gcm/server.jd
@@ -0,0 +1,160 @@
+page.title=GCM Server
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Quickview</h2>
+
+<ul>
+<li>Understand how to set up the server side of a GCM app.</li>
+<li>Become familiar with the <a href="{@docRoot}reference/com/google/android/gcm/server/package-summary.html">GCM server helper library</a>.</li>
+</ul>
+
+
+<h2>In this document</h2>
+
+<ol>
+ <li><a href="#requirements">Requirements</a> </li>
+ <li><a href="#gcm-setup">Setting Up GCM</a></li>
+ <li><a href="#server-setup">Setting Up an HTTP Server</a>
+ <ol>
+ <li><a href="#webserver-setup">Using a standard web server</a></li>
+ <li><a href="#appengine-setup">Using App Engine for Java</a></li>
+ </ol>
+ </li>
+</ol>
+
+<h2>See Also</h2>
+
+<ol class="toc">
+<li><a href="gs.html">Getting Started</a></li>
+<li><a href="client.html">GCM Client</a></li>
+<li><a href="ccs.html">Cloud Connection Server</a></li>
+
+
+</ol>
+
+</div>
+</div>
+
+
+
+
+<p>This document gives examples of GCM server-side code for HTTP. For an example of an XMPP server (<a href="ccs.html">Cloud Connection Server</a>), see <a href="gs.html#server">Getting Started</a>. Note that a full GCM implementation requires a client-side implementation, in addition to the server. For a complete working example that includes client and server-side code, see <a href="gs.html">Getting Started</a>.</a>
+
+<h2 id="requirements">Requirements</h2>
+<p>For the web server:</p>
+<ul>
+ <li> <a href="http://ant.apache.org/">Ant 1.8</a> (it might work with earlier versions, but it's not guaranteed).</li>
+ <li>One of the following:
+ <ul>
+ <li>A running web server compatible with Servlets API version 2.5, such as <a href="http://tomcat.apache.org/">Tomcat 6</a> or <a href="http://jetty.codehaus.org/">Jetty</a>, or</li>
+ <li><a href="http://code.google.com/appengine/">Java App Engine SDK</a> version 1.6 or later.</li>
+ </ul>
+ </li>
+ <li>A Google account registered to use GCM.</li>
+ <li>The API key for that account.</li>
+</ul>
+<p>For the Android application:</p>
+<ul>
+ <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
+ <li>The Google API project number of the account registered to use GCM.</li>
+</ul>
+<h2 id="gcm-setup">Setting Up GCM</h2>
+<p>Before proceeding with the server and client setup, it's necessary to register a Google account with the Google API Console, enable Google Cloud Messaging in GCM, and obtain an API key from the <a href="https://code.google.com/apis/console">Google API Console</a>.</p>
+<p>For instructions on how to set up GCM, see <a href="gs.html">Getting Started</a>.</p>
+
+
+<h2 id="server-setup">Setting Up an HTTP Server</h2>
+<p>This section describes the different options for setting up an HTTP server.</p>
+<h3 id="webserver-setup">Using a standard web server</h3>
+<p>To set up the server using a standard, servlet-compliant web server:</p>
+<ol>
+ <li>From the <a href="http://code.google.com/p/gcm">open source site</a>, download the following directories: <code>gcm-server</code>, <code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
+
+
+ <li>In a text editor, edit the <code>samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key</code> and replace the existing text with the API key obtained above.</li>
+ <li>In a shell window, go to the <code>samples/gcm-demo-server</code> directory.</li>
+ <li>Generate the server's WAR file by running <code>ant war</code>:</li>
+
+ <pre class="prettyprint">$ 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: <strong>dist/gcm-demo.war</strong>
+
+BUILD SUCCESSFUL
+Total time: 0 seconds
+</pre>
+
+ <li>Deploy the <code>dist/gcm-demo.war</code> to your running server. For instance, if you're using Jetty, copy <code>gcm-demo.war</code> to the <code>webapps</code> directory of the Jetty installation.</li>
+ <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/gcm-demo/home</code>, where <code>gcm-demo</code> is the application context and <code>/home</code> is the path of the main servlet.
+
+ </li>
+</ol>
+<p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows. </p>
+
+<p> You server is now ready.</p>
+
+<h3 id="appengine-setup">Using App Engine for Java</h3>
+
+<p>To set up the server using a standard App Engine for Java:</p>
+<ol>
+ <li>Get the files from the <a href="http://code.google.com/p/gcm">open source site</a>, as described above.</p>
+ </li>
+ <li>In a text editor, edit <code>samples/gcm-demo-appengine/src/com/google/android/gcm/demo/server/ApiKeyInitializer.java</code> and replace the existing text with the API key obtained above.
+
+ <p class="note"><strong>Note:</strong> The API key value set in that class will be used just once to create a persistent entity on App Engine. If you deploy the application, you can use App Engine's <code>Datastore Viewer</code> to change it later.</p>
+
+ </li>
+ <li>In a shell window, go to the <code>samples/gcm-demo-appengine</code> directory.</li>
+ <li>Start the development App Engine server by <code>ant runserver</code>, using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK and <code>-Dserver.host</code> to set your server's hostname or IP address:</li>
+
+<pre class="prettyprint">
+$ ant -Dsdk.dir=/opt/google/appengine-java-sdk runserver -Dserver.host=192.168.1.10
+Buildfile: gcm-demo-appengine/build.xml
+
+init:
+ [mkdir] Created dir: gcm-demo-appengine/dist
+
+copyjars:
+
+compile:
+
+datanucleusenhance:
+ [enhance] DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
+ [enhance] DataNucleus Enhancer completed with success for 0 classes. Timings : input=28 ms, enhance=0 ms, total=28 ms. Consult the log for full details
+ [enhance] DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
+
+runserver:
+ [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.jetty.JettyLogger info
+ [java] INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
+ [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
+ [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/appengine-web.xml
+ [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
+ [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/web.xml
+ [java] Jun 15, 2012 8:46:09 PM com.google.android.gcm.demo.server.ApiKeyInitializer contextInitialized
+ [java] SEVERE: Created fake key. Please go to App Engine admin console, change its value to your API Key (the entity type is 'Settings' and its field to be changed is 'ApiKey'), then restart the server!
+ [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
+ [java] INFO: The server is running at http://192.168.1.10:8080/
+ [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
+ [java] INFO: The admin console is running at http://192.168.1.10:8080/_ah/admin
+</pre>
+
+ <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/home</code>, where <code>/home</code> is the path of the main servlet.</li>
+
+ <p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows.</p>
+
+</ol>
+<p> You server is now ready.</p>
+
+
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 13d3eb3..891819b 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -132,11 +132,11 @@
<li><a href="<?cs var:toroot?>google/gcm/notifications.html">
<span class="en">User Notifications</span></a>
</li>
- <li><a href="<?cs var:toroot?>google/gcm/demo.html">
- <span class="en">Demo App Tutorial</span></a>
+ <li><a href="<?cs var:toroot?>google/gcm/client.html">
+ <span class="en">GCM Client</span></a>
</li>
- <li><a href="<?cs var:toroot?>google/gcm/helper.html">
- <span class="en">Using the Helper Libraries</span></a>
+ <li><a href="<?cs var:toroot?>google/gcm/server.html">
+ <span class="en">GCM Server</span></a>
</li>
<li><a href="<?cs var:toroot?>google/gcm/adv.html">
<span class="en">Advanced Topics</span></a>
diff --git a/docs/html/reference/com/google/android/gcm/GCMBaseIntentService.html b/docs/html/reference/com/google/android/gcm/GCMBaseIntentService.html
index b230b88..ad50a35 100644
--- a/docs/html/reference/com/google/android/gcm/GCMBaseIntentService.html
+++ b/docs/html/reference/com/google/android/gcm/GCMBaseIntentService.html
@@ -838,6 +838,9 @@
<h2>Class Overview</h2>
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;"><strong>DEPRECATED.</strong> Please use the <a href=
+"http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html"><code>GoogleCloudMessaging</code></a> API instead.</div>
+
<p itemprop="articleBody">Skeleton for application-specific <code><a href="/reference/android/app/IntentService.html">IntentService</a></code>s responsible for
handling communication from Google Cloud Messaging service.
<p>
diff --git a/docs/html/reference/com/google/android/gcm/GCMBroadcastReceiver.html b/docs/html/reference/com/google/android/gcm/GCMBroadcastReceiver.html
index 91c0994..ea36df4 100644
--- a/docs/html/reference/com/google/android/gcm/GCMBroadcastReceiver.html
+++ b/docs/html/reference/com/google/android/gcm/GCMBroadcastReceiver.html
@@ -737,6 +737,10 @@
<h2>Class Overview</h2>
+
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;"><strong>DEPRECATED.</strong> Please use the <a href=
+"http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html"><code>GoogleCloudMessaging</code></a> API instead.</div>
+
<p itemprop="articleBody"><code><a href="/reference/android/content/BroadcastReceiver.html">BroadcastReceiver</a></code> that receives GCM messages and delivers them to
an application-specific <code><a href="/reference/com/google/android/gcm/GCMBaseIntentService.html">GCMBaseIntentService</a></code> subclass.
<p>
diff --git a/docs/html/reference/com/google/android/gcm/GCMConstants.html b/docs/html/reference/com/google/android/gcm/GCMConstants.html
index cb260e0..8b782b6 100644
--- a/docs/html/reference/com/google/android/gcm/GCMConstants.html
+++ b/docs/html/reference/com/google/android/gcm/GCMConstants.html
@@ -710,6 +710,8 @@
<h2>Class Overview</h2>
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;"><strong>DEPRECATED.</strong> Please use the <a href=
+"http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html"><code>GoogleCloudMessaging</code></a> API instead.</div>
<p itemprop="articleBody">Constants used by the GCM library.
</p>
diff --git a/docs/html/reference/com/google/android/gcm/GCMRegistrar.html b/docs/html/reference/com/google/android/gcm/GCMRegistrar.html
index 545abe2..21a990f 100644
--- a/docs/html/reference/com/google/android/gcm/GCMRegistrar.html
+++ b/docs/html/reference/com/google/android/gcm/GCMRegistrar.html
@@ -713,6 +713,10 @@
<h2>Class Overview</h2>
+
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;"><strong>DEPRECATED.</strong> Please use the <a href=
+"http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html"><code>GoogleCloudMessaging</code></a> API instead.</div>
+
<p itemprop="articleBody">Utilities for device registration.
<p>
<strong>Note:</strong> this class uses a private <code><a href="/reference/android/content/SharedPreferences.html">SharedPreferences</a></code>
diff --git a/docs/html/reference/com/google/android/gcm/package-summary.html b/docs/html/reference/com/google/android/gcm/package-summary.html
index d2b05e6..6c8a993 100644
--- a/docs/html/reference/com/google/android/gcm/package-summary.html
+++ b/docs/html/reference/com/google/android/gcm/package-summary.html
@@ -642,21 +642,19 @@
<table class="jd-sumtable-expando">
<tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="/reference/com/google/android/gcm/GCMBaseIntentService.html">GCMBaseIntentService</a></td>
- <td class="jd-descrcol" width="100%">Skeleton for application-specific <code><a href="/reference/android/app/IntentService.html">IntentService</a></code>s responsible for
- handling communication from Google Cloud Messaging service. </td>
+ <td class="jd-descrcol" width="100%">DEPRECATED. </td>
</tr>
<tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="/reference/com/google/android/gcm/GCMBroadcastReceiver.html">GCMBroadcastReceiver</a></td>
- <td class="jd-descrcol" width="100%"><code><a href="/reference/android/content/BroadcastReceiver.html">BroadcastReceiver</a></code> that receives GCM messages and delivers them to
- an application-specific <code><a href="/reference/com/google/android/gcm/GCMBaseIntentService.html">GCMBaseIntentService</a></code> subclass. </td>
+ <td class="jd-descrcol" width="100%">DEPRECATED. </td>
</tr>
<tr class="alt-color api apilevel-" >
<td class="jd-linkcol"><a href="/reference/com/google/android/gcm/GCMConstants.html">GCMConstants</a></td>
- <td class="jd-descrcol" width="100%">Constants used by the GCM library. </td>
+ <td class="jd-descrcol" width="100%">DEPRECATED. </td>
</tr>
<tr class=" api apilevel-" >
<td class="jd-linkcol"><a href="/reference/com/google/android/gcm/GCMRegistrar.html">GCMRegistrar</a></td>
- <td class="jd-descrcol" width="100%">Utilities for device registration. </td>
+ <td class="jd-descrcol" width="100%">DEPRECATED. </td>
</tr>
</table>
</div>
diff --git a/docs/html/reference/gcm-packages.html b/docs/html/reference/gcm-packages.html
index 8065be9..2b5dc2d 100644
--- a/docs/html/reference/gcm-packages.html
+++ b/docs/html/reference/gcm-packages.html
@@ -623,14 +623,15 @@
<tr class="alt-color api apilevel-" >
<td class="jd-linkcol">
<a href="/reference/com/google/android/gcm/package-summary.html">com.google.android.gcm</a></td>
- <td class="jd-descrcol" width="100%"></td>
+ <td class="jd-descrcol" width="100%"><strong>DEPRECATED.</strong> Please use the <a href=
+"http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html"><code>GoogleCloudMessaging</code></a> API instead of this client helper library. See <a href="http://developer.android.com/google/gcm/client.html">GCM Client</a> for more information.</td>
</tr>
<tr class=" api apilevel-" >
<td class="jd-linkcol">
<a href="/reference/com/google/android/gcm/server/package-summary.html">com.google.android.gcm.server</a></td>
- <td class="jd-descrcol" width="100%"></td>
+ <td class="jd-descrcol" width="100%">Helper library for GCM HTTP server operations. See <a href="http://developer.android.com/google/gcm/server.html">GCM Server</a> for more information.</td>
</tr>