public async override void OnMessageReceived(RemoteMessage message) { AndroidSensusServiceHelper serviceHelper = null; try { // based on log messages, it looks like the os might destroy the service component of the application // but leave the rest of the application (e.g., the service helper) intact and resident in memory. // if this happens then the serivce helper will be present, but the service itself will be destroyed. // this may also mean that the protocols are stopped. regardless, we desire for the service to always // be running, as this ensures that the app will continue as a foreground service. so, ask the os to // start the service any time a push notification is received. this should be a no-op if the service // is already running. don't ask for the service to be stopped in case no protocols are running, as // it could just be the case that a push notification arrives late after the user has stopped protocols. AndroidSensusService.Start(false); serviceHelper = SensusServiceHelper.Get() as AndroidSensusServiceHelper; // if we just started the service above, then it's likely that the service helper will not yet be // initialized (it must be deserialized, which is slow). in this case, just bail out and wait for // the next push notification to arrive, at which time the service helper will hopefully be ready. if (serviceHelper == null) { SensusServiceHelper.Get().Logger.Log("Service helper not initialized following receipt of push notification and service start.", LoggingLevel.Normal, GetType()); return; } // acquire wake lock before this method returns to ensure that the device does not sleep prematurely, // interrupting any execution requested by the push notification. the service serviceHelper.KeepDeviceAwakeAsync().Wait(); PushNotification pushNotification = new PushNotification { Id = message.Data["id"], ProtocolId = message.Data["protocol"], Update = bool.Parse(message.Data["update"]), Title = message.Data["title"], Body = message.Data["body"], Sound = message.Data["sound"] }; // backend key might be blank string backendKeyString = message.Data["backend-key"]; if (!string.IsNullOrWhiteSpace(backendKeyString)) { pushNotification.BackendKey = new Guid(backendKeyString); } await SensusContext.Current.Notifier.ProcessReceivedPushNotificationAsync(pushNotification, CancellationToken.None); } catch (Exception ex) { SensusException.Report("Exception while processing remote notification: " + ex.Message, ex); } finally { serviceHelper?.LetDeviceSleepAsync().Wait(); } }
protected override IEnumerable <Datum> Poll(CancellationToken cancellationToken) { List <Datum> data = new List <Datum>(); if (HasValidAccessToken) { // prompt user for any missing permissions ICollection <string> missingPermissions = GetRequiredPermissionNames().Where(p => !AccessToken.CurrentAccessToken.Permissions.Contains(p)).ToArray(); if (missingPermissions.Count > 0) { _loginWait.Reset(); (AndroidSensusServiceHelper.Get() as AndroidSensusServiceHelper).GetMainActivityAsync(true, mainActivity => { if (mainActivity == null) { _loginWait.Set(); } else { mainActivity.RunOnUiThread(() => { LoginManager.Instance.LogInWithReadPermissions(mainActivity, missingPermissions); }); } }); _loginWait.WaitOne(); } GraphRequestBatch graphRequestBatch = new GraphRequestBatch(); foreach (Tuple <string, List <string> > edgeFieldQuery in GetEdgeFieldQueries()) { Bundle parameters = new Bundle(); if (edgeFieldQuery.Item2.Count > 0) { parameters.PutString("fields", string.Concat(edgeFieldQuery.Item2.Select(field => field + ",")).Trim(',')); } GraphRequest request = new GraphRequest( AccessToken.CurrentAccessToken, "/me" + (edgeFieldQuery.Item1 == null ? "" : "/" + edgeFieldQuery.Item1), parameters, HttpMethod.Get); graphRequestBatch.Add(request); } if (graphRequestBatch.Size() == 0) { SensusServiceHelper.Get().Logger.Log("Facebook request batch contained zero requests.", LoggingLevel.Normal, GetType()); } else { foreach (GraphResponse response in graphRequestBatch.ExecuteAndWait()) { if (response.Error == null) { FacebookDatum datum = new FacebookDatum(DateTimeOffset.UtcNow); JSONObject responseJSON = response.JSONObject; JSONArray jsonFields = responseJSON.Names(); bool valuesSet = false; for (int i = 0; i < jsonFields.Length(); ++i) { string jsonField = jsonFields.GetString(i); PropertyInfo property; if (FacebookDatum.TryGetProperty(jsonField, out property)) { object value = null; if (property.PropertyType == typeof(string)) { value = responseJSON.GetString(jsonField); } else if (property.PropertyType == typeof(bool?)) { value = responseJSON.GetBoolean(jsonField); } else if (property.PropertyType == typeof(DateTimeOffset?)) { value = DateTimeOffset.Parse(responseJSON.GetString(jsonField)); } else if (property.PropertyType == typeof(List <string>)) { List <string> values = new List <string>(); JSONArray jsonValues = responseJSON.GetJSONArray(jsonField); for (int j = 0; j < jsonValues.Length(); ++j) { values.Add(jsonValues.GetString(j)); } value = values; } else { throw new SensusException("Unrecognized FacebookDatum property type: " + property.PropertyType.ToString()); } if (value != null) { property.SetValue(datum, value); valuesSet = true; } } else { SensusServiceHelper.Get().Logger.Log("Unrecognized JSON field in Facebook query response: " + jsonField, LoggingLevel.Verbose, GetType()); } } if (valuesSet) { data.Add(datum); } } else { SensusServiceHelper.Get().Logger.Log("Error received while querying Facebook graph API: " + response.Error.ErrorMessage, LoggingLevel.Normal, GetType()); } } } } else { SensusServiceHelper.Get().Logger.Log("Attempted to poll Facebook probe without a valid access token.", LoggingLevel.Normal, GetType()); } return(data); }