PageRenderTime 40ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/PushSharp.Client/PushSharp.Client.MonoForAndroid.Gcm/GCMBaseIntentService.cs

https://github.com/mustafagenc/PushSharp
C# | 238 lines | 177 code | 39 blank | 22 comment | 24 complexity | b414f7d0e6a1de2aed3908bc0a61706a MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Android.App;
  6. using Android.Content;
  7. using Android.OS;
  8. using Android.Runtime;
  9. using Android.Views;
  10. using Android.Widget;
  11. using Android.Util;
  12. namespace GCMSharp.Client
  13. {
  14. [Android.Runtime.Preserve(AllMembers=true)]
  15. public abstract class GCMBaseIntentService : IntentService
  16. {
  17. const string TAG = "GCMBaseIntentService";
  18. const string WAKELOCK_KEY = "GCM_LIB";
  19. static PowerManager.WakeLock sWakeLock;
  20. static object LOCK = new object();
  21. string mSenderId;
  22. //int sCounter = 1;
  23. Random sRandom = new Random();
  24. const int MAX_BACKOFF_MS = 3600000; //1 hour
  25. string TOKEN = "";
  26. const string EXTRA_TOKEN = "token";
  27. protected GCMBaseIntentService() : base() {}
  28. public GCMBaseIntentService(string senderId) : base("GCMIntentService-" + senderId)
  29. {
  30. mSenderId = senderId;
  31. }
  32. protected abstract void OnMessage(Context context, Intent intent);
  33. protected virtual void OnDeletedMessages(Context context, int total)
  34. {
  35. }
  36. protected virtual bool OnRecoverableError(Context context, string errorId)
  37. {
  38. return true;
  39. }
  40. protected abstract void OnError(Context context, string errorId);
  41. protected abstract void OnRegistered(Context context, string registrationId);
  42. protected abstract void OnUnRegistered(Context context, string registrationId);
  43. protected override void OnHandleIntent(Intent intent)
  44. {
  45. try
  46. {
  47. var context = this.ApplicationContext;
  48. var action = intent.Action;
  49. if (action.Equals(GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK))
  50. {
  51. handleRegistration(context, intent);
  52. }
  53. else if (action.Equals(GCMConstants.INTENT_FROM_GCM_MESSAGE))
  54. {
  55. // checks for special messages
  56. var messageType = intent.GetStringExtra(GCMConstants.EXTRA_SPECIAL_MESSAGE);
  57. if (messageType != null)
  58. {
  59. if (messageType.Equals(GCMConstants.VALUE_DELETED_MESSAGES))
  60. {
  61. var sTotal = intent.GetStringExtra(GCMConstants.EXTRA_TOTAL_DELETED);
  62. if (!string.IsNullOrEmpty(sTotal))
  63. {
  64. int nTotal = 0;
  65. if (int.TryParse(sTotal, out nTotal))
  66. {
  67. Log.Verbose(TAG, "Received deleted messages notification: " + nTotal);
  68. OnDeletedMessages(context, nTotal);
  69. }
  70. else
  71. Log.Error(TAG, "GCM returned invalid number of deleted messages: " + sTotal);
  72. }
  73. }
  74. else
  75. {
  76. // application is not using the latest GCM library
  77. Log.Error(TAG, "Received unknown special message: " + messageType);
  78. }
  79. }
  80. else
  81. {
  82. OnMessage(context, intent);
  83. }
  84. }
  85. else if (action.Equals(GCMConstants.INTENT_FROM_GCM_LIBRARY_RETRY))
  86. {
  87. var token = intent.GetStringExtra(EXTRA_TOKEN);
  88. if (!string.IsNullOrEmpty(token) && !TOKEN.Equals(token))
  89. {
  90. // make sure intent was generated by this class, not by a
  91. // malicious app.
  92. Log.Error(TAG, "Received invalid token: " + token);
  93. return;
  94. }
  95. // retry last call
  96. if (GCMRegistrar.IsRegistered(context))
  97. GCMRegistrar.internalUnRegister(context);
  98. else
  99. GCMRegistrar.internalRegister(context, mSenderId);
  100. }
  101. }
  102. finally
  103. {
  104. // Release the power lock, so phone can get back to sleep.
  105. // The lock is reference-counted by default, so multiple
  106. // messages are ok.
  107. // If OnMessage() needs to spawn a thread or do something else,
  108. // it should use its own lock.
  109. lock (LOCK)
  110. {
  111. //Sanity check for null as this is a public method
  112. if (sWakeLock != null)
  113. {
  114. Log.Verbose(TAG, "Releasing Wakelock");
  115. sWakeLock.Release();
  116. }
  117. else
  118. {
  119. //Should never happen during normal workflow
  120. Log.Error(TAG, "Wakelock reference is null");
  121. }
  122. }
  123. }
  124. }
  125. internal static void RunIntentInService(Context context, Intent intent, Type classType)
  126. {
  127. lock (LOCK)
  128. {
  129. if (sWakeLock == null)
  130. {
  131. // This is called from BroadcastReceiver, there is no init.
  132. var pm = PowerManager.FromContext(context);
  133. sWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, WAKELOCK_KEY);
  134. }
  135. }
  136. Log.Verbose(TAG, "Acquiring wakelock");
  137. sWakeLock.Acquire();
  138. //intent.SetClassName(context, className);
  139. intent.SetClass(context, classType);
  140. context.StartService(intent);
  141. }
  142. private void handleRegistration(Context context, Intent intent)
  143. {
  144. var registrationId = intent.GetStringExtra(GCMConstants.EXTRA_REGISTRATION_ID);
  145. var error = intent.GetStringExtra(GCMConstants.EXTRA_ERROR);
  146. var unregistered = intent.GetStringExtra(GCMConstants.EXTRA_UNREGISTERED);
  147. Log.Debug(TAG, "handleRegistration: registrationId = " + registrationId + ", error = " + error + ", unregistered = " + unregistered);
  148. // registration succeeded
  149. if (registrationId != null)
  150. {
  151. GCMRegistrar.ResetBackoff(context);
  152. GCMRegistrar.SetRegistrationId(context, registrationId);
  153. OnRegistered(context, registrationId);
  154. return;
  155. }
  156. // unregistration succeeded
  157. if (unregistered != null)
  158. {
  159. // Remember we are unregistered
  160. GCMRegistrar.ResetBackoff(context);
  161. var oldRegistrationId = GCMRegistrar.ClearRegistrationId(context);
  162. OnUnRegistered(context, oldRegistrationId);
  163. return;
  164. }
  165. // last operation (registration or unregistration) returned an error;
  166. Log.Debug(TAG, "Registration error: " + error);
  167. // Registration failed
  168. if (GCMConstants.ERROR_SERVICE_NOT_AVAILABLE.Equals(error))
  169. {
  170. var retry = OnRecoverableError(context, error);
  171. if (retry)
  172. {
  173. int backoffTimeMs = GCMRegistrar.GetBackoff(context);
  174. int nextAttempt = backoffTimeMs / 2 + sRandom.Next(backoffTimeMs);
  175. Log.Debug(TAG, "Scheduling registration retry, backoff = " + nextAttempt + " (" + backoffTimeMs + ")");
  176. var retryIntent = new Intent(GCMConstants.INTENT_FROM_GCM_LIBRARY_RETRY);
  177. retryIntent.PutExtra(EXTRA_TOKEN, TOKEN);
  178. var retryPendingIntent = PendingIntent.GetBroadcast(context, 0, retryIntent, PendingIntentFlags.OneShot);
  179. var am = AlarmManager.FromContext(context);
  180. am.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + nextAttempt, retryPendingIntent);
  181. // Next retry should wait longer.
  182. if (backoffTimeMs < MAX_BACKOFF_MS)
  183. {
  184. GCMRegistrar.SetBackoff(context, backoffTimeMs * 2);
  185. }
  186. }
  187. else
  188. {
  189. Log.Debug(TAG, "Not retrying failed operation");
  190. }
  191. }
  192. else
  193. {
  194. // Unrecoverable error, notify app
  195. OnError(context, error);
  196. }
  197. }
  198. }
  199. }