diff --git a/C2dmSharp.Client.Sample/C2dmSharp.Client.Sample.csproj b/C2dmSharp.Client.Sample/C2dmSharp.Client.Sample.csproj
index 9d91e4d..6ed28d9 100644
--- a/C2dmSharp.Client.Sample/C2dmSharp.Client.Sample.csproj
+++ b/C2dmSharp.Client.Sample/C2dmSharp.Client.Sample.csproj
@@ -17,6 +17,7 @@
Properties\AndroidManifest.xmlTruearmeabi
+ Nonetrue
@@ -47,16 +48,14 @@
+
-
-
-
-
+
@@ -72,6 +71,9 @@
+
+
+
+
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/C2dmSharp.Client.Sample/Resources/Resource.Designer.cs b/C2dmSharp.Client.Sample/Resources/Resource.Designer.cs
index 4e42ebc..09ac7f1 100644
--- a/C2dmSharp.Client.Sample/Resources/Resource.Designer.cs
+++ b/C2dmSharp.Client.Sample/Resources/Resource.Designer.cs
@@ -15,66 +15,55 @@ namespace C2dmSharp.Client.Sample
public partial class Resource
{
- public class attr
+ public partial class Attribute
{
- private attr()
+ private Attribute()
{
}
}
- public class drawable
+ public partial class Drawable
{
// aapt resource value: 0x7f020000
public const int icon = 2130837504;
- private drawable()
+ private Drawable()
{
}
}
- public class layout
+ public partial class Id
{
- // aapt resource value: 0x7f030000
- public const int main = 2130903040;
+ // aapt resource value: 0x7f040003
+ public const int buttonRegister = 2130968579;
- private layout()
- {
- }
- }
-
- public class @string
- {
+ // aapt resource value: 0x7f040004
+ public const int textHints = 2130968580;
- // aapt resource value: 0x7f040000
- public const int click_to_register = 2130968576;
+ // aapt resource value: 0x7f040002
+ public const int textLastMessage = 2130968578;
// aapt resource value: 0x7f040001
- public const int click_to_unregister = 2130968577;
-
- // aapt resource value: 0x7f040002
- public const int app_name = 2130968578;
+ public const int textRegistrationId = 2130968577;
- // aapt resource value: 0x7f040003
- public const int hello = 2130968579;
+ // aapt resource value: 0x7f040000
+ public const int textRegistrationStatus = 2130968576;
- private @string()
+ private Id()
{
}
}
- public class id
+ public partial class Layout
{
- // aapt resource value: 0x7f050000
- public const int buttonRegister = 2131034112;
-
- // aapt resource value: 0x7f050001
- public const int buttonUnregister = 2131034113;
+ // aapt resource value: 0x7f030000
+ public const int main = 2130903040;
- private id()
+ private Layout()
{
}
}
diff --git a/C2dmSharp.Client.Sample/Resources/layout/main.axml b/C2dmSharp.Client.Sample/Resources/layout/main.axml
new file mode 100644
index 0000000..35c379e
--- /dev/null
+++ b/C2dmSharp.Client.Sample/Resources/layout/main.axml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
diff --git a/C2dmSharp.Client.Sample/Resources/layout/main.xml b/C2dmSharp.Client.Sample/Resources/layout/main.xml
deleted file mode 100644
index 9d0be1c..0000000
--- a/C2dmSharp.Client.Sample/Resources/layout/main.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
diff --git a/C2dmSharp.Client.Sample/Resources/values/strings.xml b/C2dmSharp.Client.Sample/Resources/values/strings.xml
deleted file mode 100644
index 6bf2c34..0000000
--- a/C2dmSharp.Client.Sample/Resources/values/strings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- Register for C2DM
- Unregister from C2DM
- C2dmSharp.Client.Sample
- Hello World, Click Me!
-
diff --git a/C2dmSharp.Client.Sample/SampleService.cs b/C2dmSharp.Client.Sample/SampleService.cs
new file mode 100644
index 0000000..ba1733c
--- /dev/null
+++ b/C2dmSharp.Client.Sample/SampleService.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Android.Util;
+
+namespace C2dmSharp.Client.Sample
+{
+ //You must subclass this!
+ [BroadcastReceiver(Permission = C2dmClient.GOOGLE_PERMISSION_C2DM_SEND)]
+ [IntentFilter(new string[] { C2dmClient.GOOGLE_ACTION_C2DM_INTENT_RECEIVE },
+ Categories = new string[] { "c2dmsharp.client.sample" })]
+ [IntentFilter(new string[] { C2dmClient.GOOGLE_ACTION_C2DM_INTENT_REGISTRATION },
+ Categories = new string[] { "c2dmsharp.client.sample" })]
+ //[C2dmReceiver]
+ //[C2dmReceiveIntentFilter("c2dmsharp.client.sample")]
+ //[C2dmRegistrationIntentFilter("c2dmsharp.client.sample")]
+ public class SampleBroadcastReceiver : C2dmBroadcastReceiver
+ {
+ }
+
+ [Service] //Must use the service tag
+ public class SampleService : C2dmSharp.Client.C2dmService
+ {
+ public override void OnRegistrationError(Exception ex)
+ {
+ Log.Error("C2DM-Sharp-Service", "Registration Failed: " + ex.Message);
+
+ //Create notification or do something useful
+ }
+
+ public override void OnRegistered(string registrationId)
+ {
+ Log.Info("C2DM-Sharp-Service", "Registered: " + registrationId);
+ //Send back to the server
+ // var wc = new WebClient();
+ // var result = wc.UploadString("http://your.server.com/api/register/", "POST",
+ // "{ 'registrationId' : '" + registrationId + "' }");
+
+ createNotification("C2DM# Registered...", "The device has been Registered, Tap to View!");
+ }
+
+ public override void OnUnregistered(string lastRegistrationId)
+ {
+ Log.Info("C2DM-Sharp-Service", "Unregistered: " + lastRegistrationId);
+ //Remove from the web service
+ // var wc = new WebClient();
+ // var result = wc.UploadString("http://your.server.com/api/unregister/", "POST",
+ // "{ 'registrationId' : '" + lastRegistrationId + "' }");
+
+ createNotification("C2DM# Unregistered...", "The device has been unregistered, Tap to View!");
+ }
+
+ public override void OnMessageReceived(Bundle extras)
+ {
+ Log.Info("C2DM-Sharp-Service", "Message Received!");
+
+ var msg = new StringBuilder();
+ foreach (var key in extras.KeySet())
+ msg.AppendLine(key + "=" + extras.Get(key).ToString());
+
+ //Store the message
+ var prefs = GetSharedPreferences("c2dm.client.sample", FileCreationMode.Private);
+ var edit = prefs.Edit();
+ edit.PutString("last_msg", msg.ToString());
+ edit.Commit();
+
+ createNotification("C2DM# Msg Rec'd", "Message Received for C2DM-Sharp... Tap to View!");
+ }
+
+ void createNotification(string title, string desc)
+ {
+ //Create notification
+ var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
+
+ //Create an intent to show ui
+ var uiIntent = new Intent(this, typeof(DefaultActivity));
+
+ //Create the notification
+ var notification = new Notification(Android.Resource.Drawable.SymActionEmail, title);
+
+ //Auto cancel will remove the notification once the user touches it
+ notification.Flags = NotificationFlags.AutoCancel;
+
+ //Set the notification info
+ //we use the pending intent, passing our ui intent over which will get called
+ //when the notification is tapped.
+ notification.SetLatestEventInfo(this,
+ title,
+ desc,
+ PendingIntent.GetActivity(this, 0, uiIntent, 0));
+
+ //Show the notification
+ notificationManager.Notify(1, notification);
+ }
+ }
+}
\ No newline at end of file
diff --git a/C2dmSharp.Client/C2dmBroadcastReceiver.cs b/C2dmSharp.Client/C2dmBroadcastReceiver.cs
index 789aec5..9ab242e 100644
--- a/C2dmSharp.Client/C2dmBroadcastReceiver.cs
+++ b/C2dmSharp.Client/C2dmBroadcastReceiver.cs
@@ -12,26 +12,48 @@
namespace C2dmSharp.Client
{
- //TODO: NOTE: Replace __PackageName__ with your actual package name for now!!!
- // Hoping we get something in MonoDroid that will do this automatically in the future!
- [BroadcastReceiver(Permission=C2dmBroadcastReceiver.GOOGLE_PERMISSION_C2DM_SEND)]
- [IntentFilter(new string[] { C2dmBroadcastReceiver.GOOGLE_ACTION_C2DM_INTENT_RECEIVE },
- Categories = new string[] { "c2dmsharp.client.sample" })]
- [IntentFilter(new string[] { C2dmBroadcastReceiver.GOOGLE_ACTION_C2DM_INTENT_REGISTRATION },
- Categories = new string[] { "c2dmsharp.client.sample" })]
-
- public class C2dmBroadcastReceiver : BroadcastReceiver
+ public class C2dmBroadcastReceiver : BroadcastReceiver where TService : Service
{
- public const string GOOGLE_ACTION_C2DM_INTENT_RECEIVE = "com.google.android.c2dm.permission.RECEIVE";
- public const string GOOGLE_ACTION_C2DM_INTENT_REGISTRATION = "com.google.android.c2dm.intent.REGISTRATION";
- public const string GOOGLE_PERMISSION_C2DM_SEND = "com.google.android.c2dm.permission.SEND";
+ public C2dmBroadcastReceiver()
+ : base()
+ { }
public override void OnReceive(Context context, Intent intent)
{
- var c2dmIntent = new Intent(context, typeof(C2dmService));
- c2dmIntent.PutExtras(intent.Extras);
+ var c2dmServiceIntent = new Intent(context, typeof(TService));
+ c2dmServiceIntent.PutExtras(intent.Extras);
+ c2dmServiceIntent.PutExtra("c2dm_action", intent.Action);
- context.StartService(c2dmIntent);
+ //Start our service
+ context.StartService(c2dmServiceIntent);
}
}
+
+ //For future possible use...
+ //public class C2dmReceiverAttribute : BroadcastReceiverAttribute
+ //{
+ // public C2dmReceiverAttribute()
+ // : base()
+ // {
+ // Permission = C2dmClient.GOOGLE_PERMISSION_C2DM_SEND;
+ // }
+ //}
+
+ //public class C2dmReceiveIntentFilterAttribute : IntentFilterAttribute
+ //{
+ // public C2dmReceiveIntentFilterAttribute(string packageName)
+ // : base(new string[] { C2dmClient.GOOGLE_ACTION_C2DM_INTENT_RECEIVE })
+ // {
+ // Categories = new string[] { packageName };
+ // }
+ //}
+
+ //public class C2dmRegistrationIntentFilterAttribute : IntentFilterAttribute
+ //{
+ // public C2dmRegistrationIntentFilterAttribute(string packageName)
+ // : base(new string[] { C2dmClient.GOOGLE_ACTION_C2DM_INTENT_REGISTRATION })
+ // {
+ // Categories = new string[] { packageName };
+ // }
+ //}
}
\ No newline at end of file
diff --git a/C2dmSharp.Client/C2dmClient.cs b/C2dmSharp.Client/C2dmClient.cs
index 09e4a69..f083f15 100644
--- a/C2dmSharp.Client/C2dmClient.cs
+++ b/C2dmSharp.Client/C2dmClient.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Threading;
using Android.App;
using Android.Content;
@@ -16,48 +17,43 @@ namespace C2dmSharp.Client
public class C2dmClient
{
///
- /// Raised whenever a C2DM Message is Received, includes a Bundle object with Key/Value extras data pairs
+ /// Incoming Intents have this action which indicates a Message was received
///
- public static event Action ReceiveMessage;
+ public const string GOOGLE_ACTION_C2DM_INTENT_RECEIVE = "com.google.android.c2dm.intent.RECEIVE";
///
- /// Raised whenever there is an error Registering for C2DM
+ /// Incoming Intents have this action which indicates Registration results
///
- public static event Action RegisterError;
+ public const string GOOGLE_ACTION_C2DM_INTENT_REGISTRATION = "com.google.android.c2dm.intent.REGISTRATION";
///
- /// Raised whenever the device has successfully registered for C2DM, with the Registration_ID
+ /// Use this intent to start a register request
///
- public static event Action Registered;
+ public const string GOOGLE_ACTION_C2DM_INTENT_REGISTER = "com.google.android.c2dm.intent.REGISTER";
///
- /// Raised whenever the device has successfully unregistered from C2DM
+ /// Use this intent to start an unregister request
///
- public static event Action Unregistered;
+ public const string GOOGLE_ACTION_C2DM_INTENT_UNREGISTER = "com.google.android.c2dm.intent.UNREGISTER";
+
+ ///
+ /// Permission that the BroadcastReceiver needs
+ ///
+ public const string GOOGLE_PERMISSION_C2DM_SEND = "com.google.android.c2dm.permission.SEND";
///
/// Register's the Device for C2DM Messages
///
/// Context
- public static void Register(Context context) //, string emailOfSender)
+ /// Email address whitelisted as the Sender ID for your App
+ public static void Register(Context context, string senderIdEmail)
{
- var accountManager = context.GetSystemService(Context.AccountService) as AccountManager;
-
- var accounts = accountManager.GetAccountsByType("com.google");
-
- if (accounts == null || accounts.Length <= 0)
- {
- if (C2dmClient.RegisterError != null)
- C2dmClient.RegisterError(new NoGoogleAccountsOnDeviceRegistrationException());
- else
- throw new NoGoogleAccountsOnDeviceRegistrationException();
- }
-
- var email = accounts[0].Name;
-
- Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
+ //Create our intent, with a pending intent to our app's broadcast
+ Intent registrationIntent = new Intent(GOOGLE_ACTION_C2DM_INTENT_REGISTER);
registrationIntent.PutExtra("app", PendingIntent.GetBroadcast(context, 0, new Intent(), 0));
- registrationIntent.PutExtra("sender", email);
+ registrationIntent.PutExtra("sender", senderIdEmail);
+
+ //Start intent
context.StartService(registrationIntent);
}
@@ -73,28 +69,15 @@ public static void Unregister(Context context)
}
- internal static void FireRegistered(string registrationId)
+ public static string GetRegistrationId(Context context)
{
- if (C2dmClient.Registered != null)
- C2dmClient.Registered.BeginInvoke(registrationId, null, null);
- }
+ var result = string.Empty;
- internal static void FireUnregistered()
- {
- if (C2dmClient.Unregistered != null)
- C2dmClient.Unregistered.BeginInvoke(null, null);
- }
+ //Get the shared pref for c2dmsharp, and read the registration id
+ var prefs = context.GetSharedPreferences("c2dmsharp", FileCreationMode.Private);
+ result = prefs.GetString("registration_id", string.Empty);
- internal static void FireError(Exception ex)
- {
- if (C2dmClient.RegisterError != null)
- C2dmClient.RegisterError.BeginInvoke(ex, null, null);
- }
-
- internal static void FireReceiveMessage(Bundle extras)
- {
- if (C2dmClient.ReceiveMessage != null)
- C2dmClient.ReceiveMessage.BeginInvoke(extras, null, null);
+ return result;
}
}
}
\ No newline at end of file
diff --git a/C2dmSharp.Client/C2dmService.cs b/C2dmSharp.Client/C2dmService.cs
index c29670d..c7717fa 100644
--- a/C2dmSharp.Client/C2dmService.cs
+++ b/C2dmSharp.Client/C2dmService.cs
@@ -2,43 +2,146 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Threading;
using Android.App;
using Android.Content;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+
namespace C2dmSharp.Client
{
- [Service]
- public class C2dmService : IntentService
+ public class C2dmService : Service
{
- protected override void OnHandleIntent(Android.Content.Intent intent)
+ Queue intents;
+ Thread thread;
+
+ public C2dmService()
+ : base()
+ {
+ intents = new Queue();
+ thread = null;
+ }
+
+ public override IBinder OnBind(Intent intent)
+ {
+ return default(IBinder);
+ }
+
+ public override void OnCreate()
+ {
+ base.OnCreate();
+ }
+
+ public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
- //Handle the c2dm intent, decide which it is
- if (intent.Action == C2dmBroadcastReceiver.GOOGLE_ACTION_C2DM_INTENT_REGISTRATION)
+ base.OnStartCommand(intent, flags, startId);
+
+ // Queue up the intent to be processed
+ this.intents.Enqueue(intent);
+
+ //Check if the thread needs starting
+ if (thread == null || !thread.IsAlive)
{
- var registrationId = intent.GetStringExtra("registration_id");
- if (!string.IsNullOrEmpty(registrationId))
- {
- C2dmClient.FireRegistered(registrationId);
- return;
- }
+ thread = new Thread(new ThreadStart(intentWorker));
+ thread.Start();
+ }
- var unregistered = intent.GetStringExtra("unregistered");
- if (!string.IsNullOrEmpty(unregistered))
- {
- C2dmClient.FireUnregistered();
- return;
- }
+ //Don't want this service always running
+ return StartCommandResult.NotSticky;
+ }
- var error = intent.GetStringExtra("error");
- if (!string.IsNullOrEmpty(error))
+ void intentWorker()
+ {
+ //Keep working while there are intents to process
+ while (intents.Count > 0)
+ {
+ //Get an intent off the queue
+ var intent = intents.Dequeue();
+
+ try
{
- C2dmClient.FireError(new C2dmRegistrationError(error, C2dmRegistrationError.GetErrorDescription(error)));
- return;
- }
+ //See what the action is
+ var c2dmAction = intent.GetStringExtra("c2dm_action");
+
+ //We need an action otherwise don't know what to do
+ if (string.IsNullOrEmpty(c2dmAction))
+ continue;
+
+ //Handle the c2dm intent, decide which it is
+ if (c2dmAction == C2dmClient.GOOGLE_ACTION_C2DM_INTENT_REGISTRATION)
+ {
+ var registrationId = intent.GetStringExtra("registration_id");
+
+ if (!string.IsNullOrEmpty(registrationId))
+ {
+ //Get the shared preferences, editor, and save the id
+ var prefs = GetSharedPreferences("c2dmsharp", FileCreationMode.Private);
+ var editor = prefs.Edit();
+ editor.PutString("registration_id", registrationId);
+ editor.Commit();
+
+ //Call our base method
+ this.OnRegistered(registrationId);
+ return;
+ }
+
+ var unregistered = intent.GetStringExtra("unregistered");
+
+ if (!string.IsNullOrEmpty(unregistered))
+ {
+ //Get the shared preferences, last id, editor, and clear the id
+ var prefs = GetSharedPreferences("c2dmsharp", FileCreationMode.Private);
+ var lastRegistrationId = prefs.GetString("registration_id", string.Empty);
+ var editor = prefs.Edit();
+ editor.PutString("registration_id", string.Empty);
+ editor.Commit();
+
+ this.OnUnregistered(lastRegistrationId);
+ return;
+ }
+
+ var error = intent.GetStringExtra("error");
+ if (!string.IsNullOrEmpty(error))
+ {
+ this.OnRegistrationError(new C2dmRegistrationError(error, C2dmRegistrationError.GetErrorDescription(error)));
+ return;
+ }
+ }
+ else if (c2dmAction == C2dmClient.GOOGLE_ACTION_C2DM_INTENT_RECEIVE)
+ {
+ this.OnMessageReceived(intent.Extras);
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Android.Util.Log.Error("C2DM-Sharp-BaseService", "Error Processing Intent: " + ex.Message + "\n" + ex.StackTrace);
+ }
}
- else if (intent.Action == C2dmBroadcastReceiver.GOOGLE_ACTION_C2DM_INTENT_RECEIVE)
- C2dmClient.FireReceiveMessage(intent.Extras);
+
+ //Since we have no more items left to process, stop our service
+ StopSelf();
+ }
+
+ //These methods are meant to be overridden by the referencing project
+ public virtual void OnRegistered(string registrationId)
+ {
+ }
+
+ public virtual void OnUnregistered(string lastRegistrationId)
+ {
+ }
+
+ public virtual void OnMessageReceived(Bundle extras)
+ {
+ }
+
+ public virtual void OnRegistrationError(Exception ex)
+ {
}
}
}
diff --git a/C2dmSharp.Client/Properties/AndroidManifest.xml b/C2dmSharp.Client/Properties/AndroidManifest.xml
index ff0a6b2..06f1dd9 100644
--- a/C2dmSharp.Client/Properties/AndroidManifest.xml
+++ b/C2dmSharp.Client/Properties/AndroidManifest.xml
@@ -1,7 +1,6 @@
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
+
-
\ No newline at end of file
diff --git a/C2dmSharp.Server/C2dmMessage.cs b/C2dmSharp.Server/C2dmMessage.cs
index f13dc35..38500b1 100644
--- a/C2dmSharp.Server/C2dmMessage.cs
+++ b/C2dmSharp.Server/C2dmMessage.cs
@@ -60,8 +60,8 @@ internal string GetPostData()
var sb = new StringBuilder();
sb.AppendFormat("registration_id={0}&collapse_key={1}&", //&auth={2}&",
- HttpUtility.UrlEncode(this.RegistrationId),
- HttpUtility.UrlEncode(this.CollapseKey)
+ this.RegistrationId,
+ this.CollapseKey
//HttpUtility.UrlEncode(this.GoogleLoginAuthorizationToken)
);
@@ -71,8 +71,8 @@ internal string GetPostData()
foreach (var key in this.Data.AllKeys)
{
sb.AppendFormat("data.{0}={1}&",
- HttpUtility.UrlEncode(key),
- HttpUtility.UrlEncode(this.Data[key]));
+ key,
+ this.Data[key]);
}
//Remove trailing & if necessary
diff --git a/C2dmSharp.Server/C2dmMessageTransport.cs b/C2dmSharp.Server/C2dmMessageTransport.cs
index c730f2f..47d1d1f 100644
--- a/C2dmSharp.Server/C2dmMessageTransport.cs
+++ b/C2dmSharp.Server/C2dmMessageTransport.cs
@@ -38,13 +38,16 @@ static C2dmMessageTransportResponse send(C2dmMessage msg, string googleLoginAuth
var postData = msg.GetPostData();
var webReq = (HttpWebRequest)WebRequest.Create(C2DM_SEND_URL);
- webReq.ContentLength = postData.Length;
+ //webReq.ContentLength = postData.Length;
webReq.Method = "POST";
+ webReq.ContentType = "application/x-www-form-urlencoded";
+ webReq.UserAgent = "C2DM-Sharp (version: 1.0)";
webReq.Headers.Add("Authorization: GoogleLogin auth=" + googleLoginAuthorizationToken);
using (var webReqStream = new StreamWriter(webReq.GetRequestStream(), Encoding.ASCII))
{
- webReqStream.Write(msg.GetPostData());
+ var data = msg.GetPostData();
+ webReqStream.Write(data);
webReqStream.Close();
}
@@ -98,7 +101,11 @@ static C2dmMessageTransportResponse send(C2dmMessage msg, string googleLoginAuth
throw new MessageTransportException(wrErr, result);
}
else
- result.MessageId = responseBody;
+ {
+ //Get the message ID
+ if (responseBody.StartsWith("id="))
+ result.MessageId = responseBody.Substring(3).Trim();
+ }
}
}
catch (WebException webEx)
diff --git a/C2dmSharp.Server/C2dmService.cs b/C2dmSharp.Server/C2dmService.cs
index 4ddcc9a..6305c19 100644
--- a/C2dmSharp.Server/C2dmService.cs
+++ b/C2dmSharp.Server/C2dmService.cs
@@ -317,7 +317,7 @@ private void messageTransportWork(object state)
}
catch (Exception ex)
{
-
+ //TODO: Log Error
}
}
}
diff --git a/README.markdown b/README.markdown
index 87b3f0e..208682d 100644
--- a/README.markdown
+++ b/README.markdown
@@ -8,9 +8,9 @@ C2DM-Sharp is a set of .NET Libraries for [Google Android's Cloud 2 Device Messa
+ **C2dmSharp.Client.Sample** - Sample Android app (replace __PackageName__ in broadcast receiver with c2dmsharp.client.sample before compiling!!!)
## What's Missing?
-The Client implementation, because of current MonoDroid limitations, does not generate the required AndroidManifest.xml changes in the referring application.
-I've written some of the attributes that are needed to make this happen, but if you look at C2dmBroadcastReceiver.cs you can see that you would have to replace __PackageName__ with the full package name of your application for the manifest generation to work.
-There is a bug report in to address this issue. The other issue is the generation of the required and tags in the manifest. Another bug was filed for this.
+The Client implementation, because of current MonoDroid limitations, does not completely generate the required AndroidManifest.xml changes in the referring application.
+I've written some of the attributes that are needed to make this happen, but if you look at attributes in the subclassed BroadcastReceiver in the Client sample, you can see that you would have to use your own package name for the manifest generation to work.
+There is a bug report in to address this issue. The other issue is the generation of the required and tags in the manifest. Another bug was filed for this. Here again you need to use your own package name where appropriate.
For now, it's recommended that you merge the uncommented section of the AndroidManifest.xml (replacing __PackageName__) with your Application's manifest, and then changing the line mentioned above to refer to your package name.
@@ -21,6 +21,8 @@ For now, it's recommended that you merge the uncommented section of the AndroidM
## How do I use it?
+ First, sign up for C2DM at: http://code.google.com/android/c2dm/signup.html
+ Download the source code and view the samples
++ Change your SenderID wherever relevant in the samples (eg: C2dmSharp.Client's DefaultActivity.cs in the top)
++ If you're not using the Client.Sample, make sure you add the right permissions from the sample's manifest, with your own package name in the right places. Also make sure you change the package name in your subclassed C2dmBroadcastReceiver's attributes!
+ Better instructions coming soon... ;)
## Links
@@ -29,7 +31,11 @@ For now, it's recommended that you merge the uncommented section of the AndroidM
## Changelog
-**Jan 20, 2011 @ 1:12pm**
+** Jan 22, 2011 @ 6:30pm **
++ Samples work! YMMV, you need to register your own accounts and make the changes in the right places, but I got it working here using both libraries!
++ HUGE update, lots of changes, things actually work now, too many changes to list
+
+** Jan 20, 2011 @ 1:12pm **
+ Server looks like it can actually send messages now :)
+ Added Samples for Client and Server apps
+ Server now will authenticate itself with the provided SenderID, Password, and ApplicationID
\ No newline at end of file