/// <summary> /// Puts a local notification to show calendar card /// </summary> /// <param name="dataItem">Data item.</param> private async Task UpdateNotificationForDataItem(IDataItem dataItem) { if (Log.IsLoggable(Constants.TAG, LogPriority.Verbose)) { Log.Verbose(Constants.TAG, "Updating notification for IDataItem"); } DataMapItem mapDataItem = DataMapItem.FromDataItem(dataItem); DataMap data = mapDataItem.DataMap; String description = data.GetString(Constants.DESCRIPTION); if (TextUtils.IsEmpty(description)) { description = ""; } else { // Add a space between the description and the time of the event description += " "; } String contentText; if (data.GetBoolean(Constants.ALL_DAY)) { contentText = GetString(Resource.String.desc_all_day, description); } else { String startTime = DateFormat.GetTimeFormat(this).Format(new Date(data.GetLong(Constants.BEGIN))); String endTime = DateFormat.GetTimeFormat(this).Format(new Date(data.GetLong(Constants.END))); contentText = GetString(Resource.String.desc_time_period, description, startTime, endTime); } Intent deleteOperation = new Intent(this, typeof(DeleteService)); // Use a unique identifier for the delete action. String deleteAction = "action_delete" + dataItem.Uri.ToString() + sNotificationId; deleteOperation.SetAction(deleteAction); deleteOperation.SetData(dataItem.Uri); PendingIntent deleteIntent = PendingIntent.GetService(this, 0, deleteOperation, PendingIntentFlags.OneShot); PendingIntent silentDeleteIntent = PendingIntent.GetService(this, 1, deleteOperation.PutExtra(Constants.EXTRA_SILENT, true), PendingIntentFlags.OneShot); Notification.Builder notificationBuilder = new Notification.Builder(this) .SetContentTitle(data.GetString(Constants.TITLE)) .SetContentText(contentText) .SetSmallIcon(Resource.Drawable.ic_launcher) .AddAction(Resource.Drawable.ic_menu_delete, GetText(Resource.String.delete), deleteIntent) .SetDeleteIntent(silentDeleteIntent) .SetLocalOnly(true) .SetPriority((int)NotificationPriority.Min); // Set the event owner's profile picture as the notification background Asset asset = data.GetAsset(Constants.PROFILE_PIC); if (asset != null) { if (mGoogleApiClient.IsConnected) { var assetFdResult = await WearableClass.DataApi.GetFdForAssetAsync(mGoogleApiClient, asset); if (assetFdResult.Status.IsSuccess) { Bitmap profilePic = BitmapFactory.DecodeStream(assetFdResult.InputStream); notificationBuilder.Extend(new Notification.WearableExtender().SetBackground(profilePic)); } else if (Log.IsLoggable(Constants.TAG, LogPriority.Debug)) { Log.Debug(Constants.TAG, "asset fetch failed with StatusCode: " + assetFdResult.Status.StatusCode); } } else { Log.Error(Constants.TAG, "Failed to set notification background - Client disconnected from Google Play Services"); } Notification card = notificationBuilder.Build(); (GetSystemService(Context.NotificationService).JavaCast <NotificationManager>()).Notify(sNotificationId, card); sNotificationIdByDataItemUri.Add(dataItem.Uri, sNotificationId++); } }
private static void SaveItem(IDataItem dataItem, ISharedPreferencesEditor editor, IDictionary <string, object> allPrefs) { DataMap dataMap = DataMapItem.FromDataItem(dataItem).DataMap; if (dataMap.KeySet().Count == 0 && dataItem.Uri.PathSegments.LastOrDefault() != PrefListener.KEY_SYNC_DONE) { // Testing has shown that when an item is deleted from the Data API, it // will often come through as an empty TYPE_CHANGED rather than a TYPE_DELETED. DeleteItem(dataItem.Uri, editor, allPrefs); } else { foreach (var key in dataMap.KeySet()) { Java.Lang.Object value = dataMap.Get(key); if (value == null) { if (allPrefs != null && value.Equals(allPrefs.ContainsKey(key))) { editor.Remove(key); } continue; } if (allPrefs != null && value.Equals(allPrefs[key])) { // No change to value. continue; } if (key.Equals(KEY_TIMESTAMP)) { continue; } if (value is Java.Lang.Boolean) { editor.PutBoolean(key, (bool)value); } else if (value is Java.Lang.Float) { editor.PutFloat(key, (float)value); } else if (value is Java.Lang.Integer) { editor.PutInt(key, (int)value); } else if (value is Java.Lang.Long) { editor.PutLong(key, (long)value); } else if (value is Java.Lang.String) { editor.PutString(key, (string)value); } else if (value is Java.Lang.Object javaValue && javaValue.Class.SimpleName == "String[]") { if (Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb) { editor.PutStringSet(key, (string[])value); } }
public override void OnDataChanged(DataEventBuffer dataEvents) { base.OnDataChanged(dataEvents); foreach (var ev in dataEvents) { var e = ((Java.Lang.Object)ev).JavaCast <IDataEvent>(); if (e.Type == DataEvent.TypeChanged) { String path = e.DataItem.Uri.Path; Log.Info(tag, "DataEvent path: " + path); if (path.StartsWith(StylistConstants.GetDataPath + StylistConstants.AnswerPath, StringComparison.CurrentCulture)) { CleanUpList(); DataMapItem dataMapItem = DataMapItem.FromDataItem(e.DataItem); var dataMapList = dataMapItem.DataMap.GetDataMapArrayList(StylistConstants.ListKey); Log.Info(tag, "dataMapList path: " + dataMapList.Count); foreach (var d in dataMapList) { var changedItem = new ServiceItem { AppId = d.GetString(StylistConstants.AppIdKey), FirstName = d.GetString(StylistConstants.FirstNameKey), LastName = d.GetString(StylistConstants.LastNameKey), ListType = (ServiceTypes)Enum.Parse(typeof(ServiceTypes), d.GetString(StylistConstants.ListTypeKey)), Status = (ServiceStatuses)Enum.Parse(typeof(ServiceStatuses), d.GetString(StylistConstants.ListStatusKey)), ScheduleDate = DateTime.Parse(d.GetString(StylistConstants.ScheduleDateKey)), StartServiceDate = DateTime.Parse(d.GetString(StylistConstants.StartServiceDateKey)), EndServiceDate = DateTime.Parse(d.GetString(StylistConstants.EndServiceDateKey)), IsDirty = false, }; Log.Info(tag, "add changeItem : " + changedItem.AppId); RunOnUiThread(() => { if (changedItem.Status == ServiceStatuses.READY || changedItem.Status == ServiceStatuses.CHAIR) { // int index = wearableAdapter.Items.FindIndex(i => i.AppId == changedItem.AppId); // if (index == -1) // { // index = wearableAdapter.Items.FindIndex(i => i.AppId == d.GetString(StylistConstants.TempAppIdKey)); wearableAdapter.Items.Add(changedItem); //} //else //{ // wearableAdapter.Items[index] = changedItem; //} } }); } } else if (path.StartsWith(StylistConstants.UpdateService, StringComparison.CurrentCulture)) { DataMapItem dataMapItem = DataMapItem.FromDataItem(e.DataItem); var data = dataMapItem.DataMap.GetDataMap(StylistConstants.ItemKey); Log.Info(tag, "data : " + data.GetString(StylistConstants.AppIdKey)); var changedItem = new ServiceItem { AppId = data.GetString(StylistConstants.AppIdKey), FirstName = data.GetString(StylistConstants.FirstNameKey), LastName = data.GetString(StylistConstants.LastNameKey), ListType = (ServiceTypes)Enum.Parse(typeof(ServiceTypes), data.GetString(StylistConstants.ListTypeKey)), Status = (ServiceStatuses)Enum.Parse(typeof(ServiceStatuses), data.GetString(StylistConstants.ListStatusKey)), ScheduleDate = DateTime.Parse(data.GetString(StylistConstants.ScheduleDateKey)), StartServiceDate = DateTime.Parse(data.GetString(StylistConstants.StartServiceDateKey)), EndServiceDate = DateTime.Parse(data.GetString(StylistConstants.EndServiceDateKey)), IsDirty = false, }; bool removeFromList = (changedItem.Status != ServiceStatuses.READY && changedItem.Status != ServiceStatuses.CHAIR); Log.Info(tag, "data remove from list: " + removeFromList); RunOnUiThread(() => { int index = wearableAdapter.Items.FindIndex(i => i.AppId == changedItem.AppId); if (index == -1) { index = wearableAdapter.Items.FindIndex(i => i.AppId == data.GetString(StylistConstants.TempAppIdKey)); } if (index == -1) { if (!removeFromList) { wearableAdapter.Items.Add(changedItem); } } else { if (removeFromList) { wearableAdapter.Items.RemoveAt(index); } else { wearableAdapter.Items[index] = changedItem; } } }); } } } wearableListView.GetAdapter().NotifyDataSetChanged(); }
public override void OnDataChanged(DataEventBuffer eventBuffer) { var events = FreezableUtils.FreezeIterable(eventBuffer); eventBuffer.Close(); var google_api_client = new GoogleApiClientBuilder(this) .AddApi(WearableClass.Api) .Build(); var connectionResult = google_api_client.BlockingConnect(Constants.CONNECT_TIMEOUT_MS, TimeUnit.Milliseconds); if (!connectionResult.IsSuccess) { Log.Error(TAG, "QuizListenerService failed to connect to GoogleApiClient."); return; } foreach (var ev in events) { var e = ((Java.Lang.Object)ev).JavaCast <IDataEvent> (); if (e.Type == DataEvent.TypeChanged) { var dataItem = e.DataItem; var dataMap = DataMapItem.FromDataItem(dataItem).DataMap; if (dataMap.GetBoolean(Constants.QUESTION_WAS_ANSWERED) || dataMap.GetBoolean(Constants.QUESTION_WAS_DELETED)) { continue; } string question = dataMap.GetString(Constants.QUESTION); int questionIndex = dataMap.GetInt(Constants.QUESTION_INDEX); int questionNum = questionIndex + 1; string[] answers = dataMap.GetStringArray(Constants.ANSWERS); int correctAnswerIndex = dataMap.GetInt(Constants.CORRECT_ANSWER_INDEX); Intent deleteOperation = new Intent(this, typeof(DeleteQuestionService)); deleteOperation.SetData(dataItem.Uri); PendingIntent deleteIntent = PendingIntent.GetService(this, 0, deleteOperation, PendingIntentFlags.UpdateCurrent); //first page of notification contains question as Big Text. var bigTextStyle = new Notification.BigTextStyle() .SetBigContentTitle(GetString(Resource.String.question, questionNum)) .BigText(question); var builder = new Notification.Builder(this) .SetStyle(bigTextStyle) .SetSmallIcon(Resource.Drawable.ic_launcher) .SetLocalOnly(true) .SetDeleteIntent(deleteIntent); //add answers as actions var wearableOptions = new Notification.WearableExtender(); for (int i = 0; i < answers.Length; i++) { Notification answerPage = new Notification.Builder(this) .SetContentTitle(question) .SetContentText(answers [i]) .Extend(new Notification.WearableExtender() .SetContentAction(i)) .Build(); bool correct = (i == correctAnswerIndex); var updateOperation = new Intent(this, typeof(UpdateQuestionService)); //Give each intent a unique action. updateOperation.SetAction("question_" + questionIndex + "_answer_" + i); updateOperation.SetData(dataItem.Uri); updateOperation.PutExtra(UpdateQuestionService.EXTRA_QUESTION_INDEX, questionIndex); updateOperation.PutExtra(UpdateQuestionService.EXTRA_QUESTION_CORRECT, correct); var updateIntent = PendingIntent.GetService(this, 0, updateOperation, PendingIntentFlags.UpdateCurrent); Notification.Action action = new Notification.Action.Builder( (int)question_num_to_drawable_id.Get(i), (string)null, updateIntent) .Build(); wearableOptions.AddAction(action).AddPage(answerPage); } builder.Extend(wearableOptions); Notification notification = builder.Build(); ((NotificationManager)GetSystemService(NotificationService)) .Notify(questionIndex, notification); } else if (e.Type == DataEvent.TypeDeleted) { Android.Net.Uri uri = e.DataItem.Uri; //URIs are in the form of "/question/0", "/question/1" etc. //We use the question index as the notification id. int notificationId = Java.Lang.Integer.ParseInt(uri.LastPathSegment); ((NotificationManager)GetSystemService(NotificationService)) .Cancel(notificationId); } ((NotificationManager)GetSystemService(NotificationService)) .Cancel(QUIZ_REPORT_NOTIF_ID); } google_api_client.Disconnect(); }
/// <summary> /// get's called when data from the wearable is received /// needs to be different from earlier data, which is why you need the timestamps as part of the data if you want each data point /// </summary> /// <param name="dataEvents"></param> public void OnDataChanged(DataEventBuffer dataEvents) { HeartDebugHandler.debugLog("Data changed"); var dataEvent = Enumerable.Range(0, dataEvents.Count) .Select(i => dataEvents.Get(i).JavaCast <IDataEvent>()) .FirstOrDefault(x => x.Type == DataEvent.TypeChanged && x.DataItem.Uri.Path.Equals(DataPointsPath)); if (dataEvent == null) { return; } else { var dataMapItem = DataMapItem.FromDataItem(dataEvent.DataItem); var map = dataMapItem.DataMap; string message = dataMapItem.DataMap.GetString("Message"); HeartDebugHandler.debugLog("Data received! message: " + message); string[] allDataPoints; if (message.Contains("|")) { allDataPoints = message.Split("|"); } else { allDataPoints = new[] { message }; } int teller = 0; bool stepReceived = false; bool hbReceived = false; bool hrReceived = false; foreach (string pointData in allDataPoints) { HeartDataPoint p = decodeDataPoint(pointData); if (p != null) { teller++; } if (p.heartType == HeartDataType.HeartBeat) { if (!hbReceived) { hbReceived = true; } hdata_Beat.Enqueue(p); if (hdata_Beat.Count > 50) { HeartFileHandler.saveData(hdata_Beat, HeartFileHandler.FILENAME_HEARTBEAT, dataStatusHandler); } } else if (p.heartType == HeartDataType.HeartRate) { if (!hrReceived) { hrReceived = true; } hdata_Rate.Enqueue(p); if (hdata_Rate.Count > 50) { HeartFileHandler.saveData(hdata_Rate, HeartFileHandler.FILENAME_HEARTRATE, dataStatusHandler); } } else if (p.heartType == HeartDataType.StepCount) { if (!stepReceived) { stepReceived = true; } hdata_Steps.Enqueue(p); if (hdata_Steps.Count > 50) { HeartFileHandler.saveData(hdata_Steps, HeartFileHandler.FILENAME_STEPS, dataStatusHandler); } } } if (teller > 0) { string types = ""; if (hrReceived) { types += "HR,"; } if (hbReceived) { types += "HB,"; } if (stepReceived) { types += "St"; } //updateStatusString("Data received, Types: {"+ types + "}, Amount: " + teller + "."); connectionStatusHandler.updateStatus("Data received, Types: {" + types + "}, Amount: " + teller + "."); //saveStepData();//bør nok kjøres på en mer intelligent måte } else { //updateStatusString("Invalid data received."); connectionStatusHandler.updateStatus("Invalid data received."); } } }