Your application must also register as an intent receiver for the two intents "com.google.android.c2dm.intent.RECEIVE" and "com.google.android.c2dm.intent.REGISTRATION". "com.google.android.c2dm.SEND"
2. Device and Registration
Currently C2DM is under beta testing. You need to ask for access. Here is the
link to the signup form .
If you test the following example on the emulator make sure that you use Google API 8 or later. You also have to register a Google user on the virtual device under "Settings"-> "Accounts Sync".
If you test the following example on a real device make sure that the Android Market is installed.
3. Example
Create the Android project "de.vogella.android.c2dm" with the activity "RegisterActivity". Create the following layout "main.xml" which will allow to enter your registered user id for C2DM and send a registration request to the C2DM servers.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText android:id="@+id/editText1" android:layout_height="wrap_content"
android:layout_width="match_parent" android:hint="Enter C2DM registered User"
></EditText>
<LinearLayout android:layout_height="match_parent"
android:layout_width="match_parent" android:id="@+id/linearLayout1"
android:gravity="center">
<Button android:id="@+id/button1" android:text="Register for Push
Notification"
android:layout_height="wrap_content" android:onClick="register"
android:layout_width="wrap_content"></Button>
</LinearLayout>
</LinearLayout>
3.2. Create the Google utility classes
Create the following three classes from Google. Unfortunately I was not able to find a downloadable package of these classes at Google therefore I reproduce them.
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.c2dm;
import java.io.IOException;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.util.Log;
/**
* Base class for C2D message receiver. Includes constants for the strings used
* in the protocol.
*/
public abstract class C2DMBaseReceiver extends IntentService {
private static final String C2DM_RETRY =
"com.google.android.c2dm.intent.RETRY";
public static final String REGISTRATION_CALLBACK_INTENT =
"com.google.android.c2dm.intent.REGISTRATION";
private static final String C2DM_INTENT =
"com.google.android.c2dm.intent.RECEIVE";
// Logging tag
private static final String TAG = "C2DM";
// Extras in the registration callback intents.
public static final String EXTRA_UNREGISTERED = "unregistered";
public static final String EXTRA_ERROR = "error";
public static final String EXTRA_REGISTRATION_ID = "registration_id";
public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";
public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";
public static final String ERR_INVALID_SENDER = "INVALID_SENDER";
public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
// wakelock
private static final String WAKELOCK_KEY = "C2DM_LIB";
private static PowerManager.WakeLock mWakeLock;
private final String senderId;
/**
* The C2DMReceiver class must create a no-arg constructor and pass the
* sender id to be used for registration.
*/
public C2DMBaseReceiver(String senderId) {
// senderId is used as base name for threads, etc.
super(senderId);
this.senderId = senderId;
}
/**
* Called when a cloud message has been received.
*/
protected abstract void onMessage(Context context, Intent intent);
/**
* Called on registration error. Override to provide better error messages.
*
* This is called in the context of a Service - no dialog or UI.
*/
public abstract void onError(Context context, String errorId);
/**
* Called when a registration token has been received.
*/
public void onRegistered(Context context, String registrationId)
throws IOException {
// registrationId will also be saved
}
/**
* Called when the device has been unregistered.
*/
public void onUnregistered(Context context) {
}
@Override
public final void onHandleIntent(Intent intent) {
try {
Context context = getApplicationContext();
if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
handleRegistration(context, intent);
} else if (intent.getAction().equals(C2DM_INTENT)) {
onMessage(context, intent);
} else if (intent.getAction().equals(C2DM_RETRY)) {
C2DMessaging.register(context, senderId);
}
} finally {
// Release the power lock, so phone can get back to sleep.
// The lock is reference counted by default, so multiple
// messages are ok.
// it should use it's own lock.
mWakeLock.release();
}
}
/**
* Called from the broadcast receiver. Will process the received intent,
* call handleMessage(), registered(), etc. in background threads, with a
* wake lock, while keeping the service alive.
*/
static void runIntentInService(Context context, Intent intent) {
if (mWakeLock == null) {
// This is called from BroadcastReceiver, there is no init.
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
WAKELOCK_KEY);
}
mWakeLock.acquire();
// Use a naming convention, similar with how permissions and intents are
// used. Alternatives are introspection or an ugly use of statics.
String receiver = context.getPackageName() + ".C2DMReceiver";
intent.setClassName(context, receiver);
context.startService(intent);
}
private void handleRegistration(final Context context, Intent intent) {
final String registrationId = intent
.getStringExtra(EXTRA_REGISTRATION_ID);
String error = intent.getStringExtra(EXTRA_ERROR);
String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "dmControl: registrationId = " + registrationId
+ ", error = " + error + ", removed = " + removed);
}
if (removed != null) {
// Remember we are unregistered
C2DMessaging.clearRegistrationId(context);
onUnregistered(context);
return;
} else if (error != null) {
// we are not registered, can try again
C2DMessaging.clearRegistrationId(context);
// Registration failed
Log.e(TAG, "Registration error " + error);
onError(context, error);
if ("SERVICE_NOT_AVAILABLE".equals(error)) {
long backoffTimeMs = C2DMessaging.getBackoff(context);
Log.d(TAG, "Scheduling registration retry, backoff = "
+ backoffTimeMs);
Intent retryIntent = new Intent(C2DM_RETRY);
PendingIntent retryPIntent = PendingIntent
.getBroadcast(context, 0 /* requestCode */, retryIntent,
0 /* flags */);
AlarmManager am = (AlarmManager)
context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME, backoffTimeMs,
retryPIntent);
// Next retry should wait longer.
backoffTimeMs *= 2;
C2DMessaging.setBackoff(context, backoffTimeMs);
}
} else {
try {
onRegistered(context, registrationId);
C2DMessaging.setRegistrationId(context, registrationId);
} catch (IOException ex) {
Log.e(TAG, "Registration error " + ex.getMessage());
}
}
}
}
package com.google.android.c2dm;
/*
*/
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* Helper class to handle BroadcastReciver behavior.
* - can only run for a limited amount of time - it must start a real service
* for longer activity
* - must get the power lock, must make sure it's released when all done.
*
*/
public class C2DMBroadcastReceiver extends BroadcastReceiver {
@Override
public final void onReceive(Context context, Intent intent) {
// To keep things in one place.
C2DMBaseReceiver.runIntentInService(context, intent);
setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
}
}
package com.google.android.c2dm;
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
/**
* Utilities for device registration.
*
* Will keep track of the registration token in a private preference.
*/
public class C2DMessaging {
public static final String EXTRA_SENDER = "sender";
public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
public static final String REQUEST_UNREGISTRATION_INTENT =
"com.google.android.c2dm.intent.UNREGISTER";
public static final String REQUEST_REGISTRATION_INTENT =
"com.google.android.c2dm.intent.REGISTER";
public static final String LAST_REGISTRATION_CHANGE =
"last_registration_change";
public static final String BACKOFF = "backoff";
public static final String GSF_PACKAGE = "com.google.android.gsf";
// package
static final String PREFERENCE = "com.google.android.c2dm";
private static final long DEFAULT_BACKOFF = 30000;
/**
* Initiate c2d messaging registration for the current application
*/
public static void register(Context context,
String senderId) {
Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
registrationIntent.setPackage(GSF_PACKAGE);
registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
registrationIntent.putExtra(EXTRA_SENDER, senderId);
context.startService(registrationIntent);
// TODO: if intent not found, notification on need to have GSF
}
/**
* Unregister the application. New messages will be blocked by server.
*/
public static void unregister(Context context) {
Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT);
regIntent.setPackage(GSF_PACKAGE);
regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
PendingIntent.getBroadcast(context,
0, new Intent(), 0));
context.startService(regIntent);
}
/**
* Return the current registration id.
*
* If result is empty, the registration has failed.
*
* @return registration id, or empty string if the registration is not complete.
*/
public static String getRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
String registrationId = prefs.getString("dm_registration", "");
return registrationId;
}
public static long getLastRegistrationChange(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
return prefs.getLong(LAST_REGISTRATION_CHANGE, 0);
}
static long getBackoff(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
return prefs.getLong(BACKOFF, DEFAULT_BACKOFF);
}
static void setBackoff(Context context, long backoff) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putLong(BACKOFF, backoff);
editor.commit();
}
// package
static void clearRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", "");
editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMillis());
editor.commit();
}
// package
static void setRegistrationId(Context context, String registrationId) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", registrationId);
editor.commit();
}
}
3.3. Getting ready for registration
Create the following class "C2DMReceiver" which we will later register as a service.
package de.vogella.android.c2dm;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.google.android.c2dm.C2DMBaseReceiver;
public class C2DMReceiver extends C2DMBaseReceiver {
public C2DMReceiver() {
// Email address currently not used by the C2DM Messaging framework
super("dummy@google.com");
}
@Override
public void onRegistered(Context context, String registrationId)
throws java.io.IOException {
// The registrationId should be send to your applicatioin server.
// We just log it to the LogCat view
// We will copy it from there
Log.e("C2DM", "Registration ID arrived: Fantastic!!!");
Log.e("C2DM", registrationId);
};
@Override
protected void onMessage(Context context, Intent intent) {
Log.e("C2DM", "Message: Fantastic!!!");
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null) {
System.out.println(extras.get("payload"));
// Now do something smart based on the information
}
}
@Override
public void onError(Context context, String errorId) {
Log.e("C2DM", "Error occured!!!");
}
}
Create the following "AndroidManifest.xml". That will register the right receivers and requests the right permissions.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.c2dm" android:versionCode="1"
android:versionName="1.0">
<permission android:name="de.vogella.android.c2dm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="de.vogella.android.c2dm.permission.C2D_MESSAGE" />
<!-- Permissions -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name="RegisterActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".C2DMReceiver" />
<!-- Only C2DM servers can send messages for the app. If permission is
not set - any other app can generate it -->
<receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="de.vogella.android.c2dm" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="de.vogella.android.c2dm" />
</intent-filter>
</receiver>
</application>
</manifest>
Change your Activity to the following. In this activity you can enter your registered Google C2DM user and ask for a registration key.
package de.vogella.android.c2dm;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.google.android.c2dm.C2DMessaging;
public class RegisterActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void register(View view) {
Log.e("Super", "Starting registration");
Toast.makeText(this, "Starting", Toast.LENGTH_LONG).show();
EditText text = (EditText) findViewById(R.id.editText1);
C2DMessaging.register(this, text.getText().toString());
}
}
3.4. Register your application
Run your application, maintain your registered user and press the button. Check LogCat for the registration ID.
If you see " Unable to start service Intent { act=com.google.android.c2dm.intent.REGISTER pkg=com.google.android.gsf (has extras) }: not found" message make sure you are using a Google device and that you have a Google user registered on the device.
If you run a Linux system you can easily test the service on teh command line. You can request your authentication key via
curl on the command line. From the response get the part after "Auth=".
curl https://www.google.com/accounts/ClientLogin -d
Email=your_user -d "Passwd=your_password" -d
accountType=GOOGLE -d source=Google-cURL-Example -d service=ac2dm
This part and the registration code can be used to send a message to your device.
curl --header "Authorization: GoogleLogin auth=your_authenticationid" "
https://android.apis.google.com/c2dm/send"
-d registration_id=your_registration -d "data.payload=This data will be send
to your application as payload" -d collapse_key=0
3.6. Create your server ;-) application
As described earlier the application server needs to get an authentication key via HTTPS. Afterwards it can send messages to the device via HTTP by supplying the authentication key and the registration ID.
To avoid that you have to learn about
server side Java programming we will "simulate" the server by another Android application. In general you could create a server side application for example with the
Google App Engine .
Create a new Android application "de.vogella.android.c2dm.server" with the Activity "ServerSimulator". Assign the permission "android.permission.INTERNET" to this activity.
Change "main.xml" to the following.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button android:text="Get Authentication" android:id="@+id/button1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="getAuthentification"></Button>
<Button android:text="Show Authentication" android:id="@+id/button2"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="showAuthentification"></Button>
<EditText android:layout_width="match_parent" android:id="@+id/registrationId"
android:hint="Registration Code" android:layout_height="wrap_content"></EditText>
<Button android:text="Send Message" android:id="@+id/button3"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="sendMessage"></Button>
</LinearLayout>
Change "ServerSimulator" to the following. Make your to use your registration key, your user and your password.
package de.vogella.android.c2dm.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class ServerSimulator extends Activity {
private SharedPreferences prefManager;
private final static String AUTH = "authentication";
private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
public static final String PARAM_REGISTRATION_ID = "registration_id";
public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
public static final String PARAM_COLLAPSE_KEY = "collapse_key";
private static final String UTF8 = "UTF-8";
// Registration is currently hardcoded
private final static String YOUR_REGISTRATION_STRING = "APA91bFQut1tqA-
nIL1ZaV0emnp4Rb0smwCkrMHcoYRXeYVtIebJgrzOHQj0h76qKRzd3bC_JO37uJ
0NgTcFO87HS9V7YC-yOP774pm0toppTHFO7Zc_PAw";
private SharedPreferences prefs;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
prefManager = PreferenceManager.getDefaultSharedPreferences(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.mymenu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menuitem_user:
Intent intent = new Intent(this, UserPreferences.class);
startActivity(intent);
break;
default:
break;
}
return false;
}
public void getAuthentification(View view) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(this);
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(
"https://www.google.com/accounts/ClientLogin");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("Email", prefs.getString(
"user", "undefined")));
nameValuePairs.add(new BasicNameValuePair("Passwd", prefs
.getString("password", "undefined")));
nameValuePairs.add(new BasicNameValuePair("accountType", "GOOGLE"));
nameValuePairs.add(new BasicNameValuePair("source",
"Google-cURL-Example"));
nameValuePairs.add(new BasicNameValuePair("service", "ac2dm"));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
Log.e("HttpResponse", line);
if (line.startsWith("Auth=")) {
Editor edit = prefManager.edit();
edit.putString(AUTH, line.substring(5));
edit.commit();
String s = prefManager.getString(AUTH, "n/a");
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void showAuthentification(View view) {
String s = prefManager.getString(AUTH, "n/a");
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
public void sendMessage(View view) {
try {
Log.e("Tag", "Started");
String auth_key = prefManager.getString(AUTH, "n/a");
// Send a sync message to this Android device.
StringBuilder postDataBuilder = new StringBuilder();
postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
.append(YOUR_REGISTRATION_STRING);
// if (delayWhileIdle) {
// postDataBuilder.append("&").append(PARAM_DELAY_WHILE_IDLE)
// .append("=1");
// }
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
.append("0");
postDataBuilder.append("&").append("data.payload").append("=")
.append(URLEncoder.encode("Lars war hier", UTF8));
byte[] postData = postDataBuilder.toString().getBytes(UTF8);
// Hit the dm URL.
URL url = new URL("https://android.clients.google.com/c2dm/send");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",
Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="
+ auth_key);
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int responseCode = conn.getResponseCode();
Log.e("Tag", String.valueOf(responseCode));
// Validate the response code
if (responseCode == 401 || responseCode == 403) {
// The token is too old - return false to retry later, will
// fetch the token
// from DB. This happens if the password is changed or token
// expires. Either admin
// is updating the token, or Update-Client-Auth was received by
// another server,
// and next retry will get the good one from database.
Log.e("C2DM", "Unauthorized - need token");
}
// Check for updated token header
String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
if (updatedAuthToken != null && !auth_key.equals(updatedAuthToken)) {
Log.i("C2DM",
"Got updated auth token from datamessaging servers: "
+ updatedAuthToken);
Editor edit = prefManager.edit();
edit.putString(AUTH, updatedAuthToken);
}
String responseLine = new BufferedReader(new InputStreamReader(
conn.getInputStream())).readLine();
// NOTE: You *MUST* use exponential backoff if you receive a 503
// response code.
// Since App Engine's task queue mechanism automatically does this
// for tasks that
// return non-success error codes, this is not explicitly
// implemented here.
// If we weren't using App Engine, we'd need to manually implement
// this.
if (responseLine == null || responseLine.equals("")) {
Log.i("C2DM", "Got " + responseCode
+ " response from Google AC2DM endpoint.");
throw new IOException(
"Got empty response from Google AC2DM endpoint.");
}
String[] responseParts = responseLine.split("=", 2);
if (responseParts.length != 2) {
Log.e("C2DM", "Invalid message from google: " + responseCode
+ " " + responseLine);
throw new IOException("Invalid response from Google "
+ responseCode + " " + responseLine);
}
if (responseParts[0].equals("id")) {
Log.i("Tag", "Successfully sent data message to device: "
+ responseLine);
}
if (responseParts[0].equals("Error")) {
String err = responseParts[1];
Log.w("C2DM",
"Got error response from Google datamessaging endpoint: "
+ err);
// No retry.
throw new IOException(err);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}