Implementing
your C2DM Client :
 
C2DM Client(Android):
First we are going to implement our client side. It will receive the message from Google server and show a notification on the status bar Currently this code will show a notification on the status bar . In the C2DM client we need to provide the registered
eMail id to get the Registration key for the client .
Go to the link and register your e-mail id with your application Package name (Do remember the Package name its very important )
http://code.google.com/android/c2dm/signup.html
You will receive a mail from C2DM giving your C2DM account status.
The most important part is the AndroidManifest.xml be vary careful while making changes .
 
src/
C2DMRegistration.java
public class C2DMRegistration {  
   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";  
   public static final String TAG = "REGISTRATION FOR C2DM";  
   // package  
   static final String PREFERENCE = "com.google.android.c2dm";  
     
   public static long DEFAULT_BACKOFF = 3000;  
 
   /** 
    * Initiate c2d messaging registration for the current application 
    */  
   public static void register(Context context  
           ) {  
    String mailId=context.getString(R.string.email_id);
       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, mailId);  
       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();  
 
   }  
 
   
}  
C2DMBaseReceiver.java
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  
    public static final String WAKELOCK_KEY = "C2DM_LIB";  
  
    public static PowerManager.WakeLock mWakeLock;  
    public 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. 
     */  
    public 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)) {  
                C2DMRegistration.register(context);  
            }  
        } finally {  
            // Release the power lock, so phone can get back to sleep.  
            // The lock is reference counted by default, so multiple  
            // messages are ok.  
  
            // If the onMessage() needs to spawn a thread or do something else,  
            // 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 = "com.android.aspark.notification.C2DMReceiver";
        String receiver = context.getPackageName() + ".C2DMReceiver";  
        intent.setClassName(context, receiver);  
  
        context.startService(intent);  
  
    }  
  
    public 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  
            C2DMRegistration.clearRegistrationId(context);  
            onUnregistered(context);  
            return;  
  } else if (error != null) {
   // we are not registered, can try again
   C2DMRegistration.clearRegistrationId(context);
   // Registration failed
   Log.e(TAG, "Registration error1 " + error);
   onError(context, error);
   if ("SERVICE_NOT_AVAILABLE".equals(error)) {
    long backoffTimeMs = C2DMRegistration.getBackoff(context);  
    
    Log.d(TAG, "Scheduling registration retry, backoff = "
      + backoffTimeMs);
    Log.i(TAG, "Registration retrying ");
    Intent Intent = new Intent(C2DM_RETRY);
    PendingIntent PIntent = PendingIntent
      .getBroadcast(context, 0 /* requestCode */, Intent,
        0 /* flags */);
//
    AlarmManager am = (AlarmManager) context
      .getSystemService(Context.ALARM_SERVICE);
    Log.i(TAG, "Starting Alarm  ");
    am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+backoffTimeMs,
      PIntent);
    Log.e(TAG," allerm set on  "+ backoffTimeMs);
    
//    // Next retry should wait longer.   
    backoffTimeMs*=2;
    C2DMRegistration.setBackoff(context, backoffTimeMs);
   }
        } else {  
            try {  
                onRegistered(context, registrationId);  
                C2DMRegistration.setRegistrationId(context, registrationId);  
            } catch (IOException ex) {  
                Log.e(TAG, "Registration error2 " + ex.getMessage());  
            }  
        }  
    }  
  
}  
C2DMBroadcastReceiver.java
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 */);          
    }  
}  
C2DMReceiver.java
public class C2DMReceiver extends C2DMBaseReceiver {  
 
 public static String registrationID=null;
 
    public C2DMReceiver() {  
        // Email address currently not used by the C2DM Messaging framework  
     
        super("xxx");  
    }  
     
    /* (non-Javadoc)
     * @see com.android.aspark.notification.C2DMBaseReceiver#onRegistered(android.content.Context, java.lang.String)
     */
    @Override  
    public void onRegistered(Context context, String registrationId)  
            throws java.io.IOException {  
     registrationID=registrationId;
        Log.e("C2DM", "Registration ID arrived: Fantastic!!!");  
        Log.e("C2DM", registrationId);  
        //--------------------server call------------------------------------
       
        String buildVersion = Build.VERSION.RELEASE;
       
        Log.i("device type", deviceType );
       
       
         };  
  
 /* (non-Javadoc)
  * @see com.android.aspark.notification.C2DMBaseReceiver#onMessage(android.content.Context, android.content.Intent)
  */
 @Override
 public void onMessage(Context context, Intent intent) {
  String action = intent.getAction();
  // On Notification recived extract the Message
  // "Payload"..............................
  Log.w("C2DM", "Message Receiver called");
  if ("com.google.android.c2dm.intent.RECEIVE".equals(action)) {
   Log.w("C2DM", "Received message");
   // extracting the payload data with key value ...........
   final String payload = intent.getStringExtra("payload");
   // expecting a unique notification id from server.......................  
   final int notificationID=Integer.parseInt(intent.getStringExtra("notificationid"));
  }
   
   Log.d("C2DM", "dmControl: payload = " + payload);
   Log.d("C2DM", "dmControl: notificationID = " + notificationID);
      //Auto incrementing for testing 
  
   
   // Note: Send this to my application server to get the real data
   // Lets make something visible to show that we received the message
   createNotification(context, payload,notificationID);
  }
  Log.e("C2DM", "Message Recived : Fantastic!!!");
 }
  
    @Override  
    public void onError(Context context, String errorId) {  
        Log.e("C2DM", "Error occured!!!");  
    }  
    
    
 /**
  * ---------------Displaying Notification on status bar ---------------------
  * @param context
  * @param payload
  */
 public void createNotification(Context context, String payload,int notificationID) {
  
  String ns = Context.NOTIFICATION_SERVICE;
  NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
  
  int icon = R.drawable.notification_icon;
  CharSequence tickerText = "New Message";
  long when = System.currentTimeMillis();
  Notification notification = new Notification(icon, tickerText, when);
   
  CharSequence contentTitle = "";
  CharSequence contentText = payload;
  Intent notificationIntent = new Intent(this,OnMessageReceiveActivity.class);
  notificationIntent.putExtra("payload", payload);
  notificationIntent.putExtra("notificationid", ""+notificationID);
  
  PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
  notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
  
  mNotificationManager.notify(notificationID, notification);
  
 }
 
 
}  
OnMessageReceiveActivity.java
public class OnMessageReceiveActivity extends Activity{
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.onmessagereceiveactivity);
 }
}
RegisterActivity.java
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();
  C2DMRegistration.register(this);
 }
}
res/
onmessagereceiveactivity.xml
<?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">  
    <TextView android:id="@+id/editText1" android:layout_height="wrap_content"  
        android:layout_width="match_parent" android:text="You are in new activity" 
   
        ></TextView>  
    
  
</LinearLayout> 
main.xml
<?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:id="@+id/button1" android:text="Register for Push Notification"  
            android:layout_height="wrap_content" android:onClick="register"  
            android:layout_width="wrap_content"></Button>  
  
</LinearLayout>  
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="YOUR_PACKAGE_NAME"
    android:versionCode="1"
    android:versionName="1.0" >
    <permission
        android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="YOUR_PACKAGE_NAME.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.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 <uses-permission android:name="android.permission.ACCESS_CORSE_LOCATION"/>
    <application
        android:icon="@drawable/ic_launcher"
        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>
<activity  android:name=".OnMessageReceiveActivity"/>
        <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=".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="YOUR_PACKAGE_NAME" />
            </intent-filter>
            <!-- Receive the registration id -->
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="YOUR_PACKAGE_NAME" />
                </intent-filter>
        </receiver>
        
      <receiver
            android:name=".C2DMBroadcastReceiver"
            >
                <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RETRY"/>
                <category android:name="YOUR_PACKAGE_NAME" />
            </intent-filter>
                          
            
        </receiver>
    </application>
</manifest>
You need to declare few more things
 
 
 
Value
-> 
String
:
<string
name="email_id"></string> 
 
 
 
DRAWABLE:
1.notification_icon.png 
Now you can run your Android Client , in response you will get the auth KEY( hash value ) . Check your LogCat  .Do not change the permission and package name in manifest file.
*It will show the notifications on the status bar with a fixed message ,it will not show the message that is sent from the server side.
*for server side check my other post .C2DM Server.
Enjoy.... 
 
Do post your doubts, queries or suggestions in this blog.