Skip to content

Commit

Permalink
Initial Commit of Code
Browse files Browse the repository at this point in the history
Very early, untested code!  Use at your own risk!
  • Loading branch information
Redth committed Jun 15, 2012
1 parent 4ab5e72 commit 23a6baf
Show file tree
Hide file tree
Showing 56 changed files with 3,806 additions and 6 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ bin
obj

# mstest test results
TestResults
TestResults

.suo
99 changes: 99 additions & 0 deletions PushSharp.Android/AndroidNotification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web;
using PushSharp.Common;

namespace PushSharp.Android
{
public class AndroidNotification : Notification
{
public AndroidNotification()
{
this.Platform = PlatformType.Android;

this.RegistrationId = string.Empty;
this.CollapseKey = string.Empty;
this.Data = new NameValueCollection();
this.DelayWhileIdle = null;
}

/// <summary>
/// Registration ID of the Device
/// </summary>
public string RegistrationId
{
get;
set;
}

/// <summary>
/// Only the latest message with the same collapse key will be delivered
/// </summary>
public string CollapseKey
{
get;
set;
}

/// <summary>
/// Key/Value pairs to be sent to the Device (as extras in the Intent)
/// </summary>
public NameValueCollection Data
{
get;
set;
}

/// <summary>
/// If true, C2DM will only be delivered once the device's screen is on
/// </summary>
public bool? DelayWhileIdle
{
get;
set;
}

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)
//HttpUtility.UrlEncode(this.GoogleLoginAuthorizationToken)
);

if (this.DelayWhileIdle.HasValue)
sb.AppendFormat("delay_while_idle={0}&", this.DelayWhileIdle.Value ? "true" : "false");

foreach (var key in this.Data.AllKeys)
{
sb.AppendFormat("data.{0}={1}&",
HttpUtility.UrlEncode(key),
HttpUtility.UrlEncode(this.Data[key]));
}

//Remove trailing & if necessary
if (sb.Length > 0 && sb[sb.Length - 1] == '&')
sb.Remove(sb.Length - 1, 1);

return sb.ToString();
}

internal int GetMessageSize()
{
//http://groups.google.com/group/android-c2dm/browse_thread/thread/c70575480be4f883?pli=1
// suggests that the max size of 1024 bytes only includes
// only char counts of: keys, values, and the collapse_data value
int size = HttpUtility.UrlEncode(this.CollapseKey).Length;

foreach (var key in this.Data.AllKeys)
size += HttpUtility.UrlEncode(key).Length + HttpUtility.UrlEncode(this.Data[key]).Length;

return size;
}
}
}
106 changes: 106 additions & 0 deletions PushSharp.Android/AndroidPushChannel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Text;
using PushSharp.Common;

namespace PushSharp.Android
{
public class AndroidPushChannel : PushChannelBase
{
AndroidPushChannelSettings androidSettings = null;
string googleAuthToken = string.Empty;
C2dmMessageTransportAsync transport;

public AndroidPushChannel(AndroidPushChannelSettings settings) : base(settings)
{
androidSettings = settings;

//Go get the auth token from google
try
{
RefreshGoogleAuthToken();
}
catch (GoogleLoginAuthorizationException glaex)
{
this.Events.RaiseChannelException(glaex);
}

transport = new C2dmMessageTransportAsync();
transport.UpdateGoogleClientAuthToken += new Action<string>((newToken) =>
{
this.googleAuthToken = newToken;
});

transport.MessageResponseReceived += new Action<C2dmMessageTransportResponse>(transport_MessageResponseReceived);

transport.UnhandledException += new Action<AndroidNotification, Exception>(transport_UnhandledException);
}

void transport_UnhandledException(AndroidNotification notification, Exception exception)
{
this.Events.RaiseChannelException(exception);
}

void transport_MessageResponseReceived(C2dmMessageTransportResponse response)
{
if (response.ResponseStatus == MessageTransportResponseStatus.Ok)
this.Events.RaiseNotificationSent(response.Message);
else if (response.ResponseStatus == MessageTransportResponseStatus.InvalidRegistration)
{
//Device subscription is no good!
this.Events.RaiseDeviceSubscriptionExpired(PlatformType.Android, response.Message.RegistrationId);
}
else
{
//TODO: Raise error response
this.Events.RaiseNotificationSendFailure(response.Message, new Exception(response.ResponseStatus.ToString()));
}
}

protected override void SendNotification(Notification notification)
{
transport.Send(notification as AndroidNotification, this.googleAuthToken, androidSettings.SenderID, androidSettings.ApplicationID);
}


/// <summary>
/// Explicitly refreshes the Google Auth Token. Usually not necessary.
/// </summary>
public void RefreshGoogleAuthToken()
{
string authUrl = "https://www.google.com/accounts/ClientLogin";

var data = new NameValueCollection();

data.Add("Email", this.androidSettings.SenderID);
data.Add("Passwd", this.androidSettings.Password);
data.Add("accountType", "GOOGLE_OR_HOSTED");
data.Add("service", "ac2dm");
data.Add("source", this.androidSettings.ApplicationID);

var wc = new WebClient();

try
{
var authStr = Encoding.ASCII.GetString(wc.UploadValues(authUrl, data));

//Only care about the Auth= part at the end
if (authStr.Contains("Auth="))
googleAuthToken = authStr.Substring(authStr.IndexOf("Auth=") + 5);
else
throw new GoogleLoginAuthorizationException("Missing Auth Token");
}
catch (WebException ex)
{
var result = "Unknown Error";
try { result = (new System.IO.StreamReader(ex.Response.GetResponseStream())).ReadToEnd(); }
catch { }

throw new GoogleLoginAuthorizationException(result);
}
}
}
}
23 changes: 23 additions & 0 deletions PushSharp.Android/AndroidPushChannelSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PushSharp.Common;

namespace PushSharp.Android
{
public class AndroidPushChannelSettings : PushChannelSettings
{
public AndroidPushChannelSettings(string senderID, string password, string applicationID)
{
this.SenderID = senderID;
this.Password = password;
this.ApplicationID = applicationID;
}

public string SenderID { get; private set; }
public string Password { get; private set; }

public string ApplicationID { get; private set; }
}
}
21 changes: 21 additions & 0 deletions PushSharp.Android/AndroidPushService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PushSharp.Common;

namespace PushSharp.Android
{
public class AndroidPushService : PushServiceBase
{
public AndroidPushService(PushChannelSettings channelSettings, PushServiceSettings serviceSettings = null)
: base(channelSettings, serviceSettings)
{
}

protected override PushChannelBase CreateChannel(PushChannelSettings channelSettings)
{
return new AndroidPushChannel(channelSettings as AndroidPushChannelSettings);
}
}
}
Loading

0 comments on commit 23a6baf

Please sign in to comment.