Commit 2632dbdf authored by Lucas Braz Cunha's avatar Lucas Braz Cunha

AGILE#307: Done service to update notification's status to read.

Signed-off-by: Lucas Braz Cunha's avatarLucas B. Cunha <lbc16@inf.ufpr.br>
parent ff00deb7
......@@ -49,6 +49,15 @@
</intent-filter>
</service>
<service
android:name=".services.notification.NotificationReadService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>
<service
android:name=".services.notification.NotificationCreateService"
android:exported="false"
......
......@@ -221,7 +221,7 @@ public class LoginActivity extends AppCompatActivity implements LoginView {
Job job = dispatcher.newJobBuilder()
.setService(NotificationsListService.class)
.setTag(Utils.NOTIFICATION_UPDATE_SERVICE)
.setTag(Utils.NOTIFICATION_UPDATE_LIST_SERVICE)
//time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600
//will be repeated every 10 minutes
.setTrigger(Trigger.executionWindow(/*600, 720*/1, 29))
......
......@@ -390,7 +390,7 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S
notification.reminderTime = sdfServer.format(schedule.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()]) - (reminderTimeArray[sp_notification.getSelectedItemPosition()]));
if(rb_yes.isChecked()){
notification.emailAddres = et_email.getText().toString();
notification.emailAddress = et_email.getText().toString();
}
scheduleConfirmationPresenter.createNotification(notification);
......
......@@ -122,7 +122,8 @@ public abstract class Utils {
public static final String NOTIFICATION = "notification";
public static final String NOTIFICATION_SERVICE = "br.c3sl.ufpr.notification_service";
public static final String NOTIFICATION_UPDATE_SERVICE = "br.c3sl.ufpr.notification_update_service";
public static final String NOTIFICATION_UPDATE_LIST_SERVICE = "br.c3sl.ufpr.notification_update_service";
public static final String NOTIFICATION_READ_SERVICE = "br.c3sl.ufpr.notification_read_service";
public static final String NOTIFICATION_LIST = "notification_list";
......
......@@ -25,7 +25,7 @@ public class Notification implements Parcelable{
public String description;
@SerializedName("reminder_email")
public String emailAddres;
public String emailAddress;
@SerializedName("email_sent")
public boolean emailSent;
......@@ -39,7 +39,7 @@ public class Notification implements Parcelable{
this.reminderTime = reminderTime;
this.hasRead = hasRead;
this.description = description;
this.emailAddres = emailAddress;
this.emailAddress = emailAddress;
this.emailSent = emailSent;
}
......@@ -49,7 +49,7 @@ public class Notification implements Parcelable{
reminderTime = pc.readString();
hasRead = pc.readByte() != 0;
description = pc.readString();
emailAddres = pc.readString();
emailAddress = pc.readString();
emailSent = pc.readByte() != 0;
}
......@@ -76,7 +76,7 @@ public class Notification implements Parcelable{
dest.writeString(reminderTime);
dest.writeByte((byte) (hasRead ? 1 : 0));
dest.writeString(description);
dest.writeString(emailAddres);
dest.writeString(emailAddress);
dest.writeByte((byte) (emailSent ? 1 : 0));
}
......
package br.ufpr.c3sl.agendador.agendador.models;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.SerializedName;
/**
* Created by Lucas Braz Cunha on 18/12/17.
*/
public class NotificationReturn{
public class NotificationReturn implements Parcelable{
@SerializedName("id")
public long notificationId;
......@@ -30,7 +33,7 @@ public class NotificationReturn{
public String description;
@SerializedName("reminder_email")
public String emailAddres;
public String emailAddress;
@SerializedName("reminder_email_sent")
public int emailSent;
......@@ -42,4 +45,50 @@ public class NotificationReturn{
public String updatedAt;
/**reads back fields IN THE ORDER they were written */
private NotificationReturn(Parcel pc){
notificationId = pc.readLong();
accountId = pc.readLong();
scheduleId = pc.readLong();
resourceScheduleId = pc.readLong();
reminderTime = pc.readString();
hasRead = pc.readInt();
description = pc.readString();
emailAddress = pc.readString();
emailSent = pc.readInt();
createdAt = pc.readString();
updatedAt = pc.readString();
}
/** Static field used to regenerate object, individually or as arrays */
public static final Parcelable.Creator<NotificationReturn> CREATOR = new Parcelable.Creator<NotificationReturn>() {
public NotificationReturn createFromParcel(Parcel pc) {
return new NotificationReturn(pc);
}
public NotificationReturn[] newArray(int size) {
return new NotificationReturn[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(notificationId);
dest.writeLong(accountId);
dest.writeLong(scheduleId == null ? 0 : scheduleId);
dest.writeLong(resourceScheduleId == null ? 0 : resourceScheduleId);
dest.writeString(reminderTime == null ? "" : reminderTime);
dest.writeInt(hasRead);
dest.writeString(description == null ? "" : description);
dest.writeString(emailAddress == null ? "" : emailAddress);
dest.writeInt(emailSent);
dest.writeString(createdAt == null ? "" : createdAt);
dest.writeString(updatedAt == null ? "" : updatedAt);
}
}
package br.ufpr.c3sl.agendador.agendador.models;
import android.content.Context;
import com.google.gson.annotations.SerializedName;
/**
* Created by Lucas Braz Cunha on 22/01/18.
*
* Model used to update notification status to "read".
*
*/
public class NotificationUpdate {
@SerializedName("notification")
private NotificationUpdateContent content;
public NotificationUpdate(int hasRead){
content = new NotificationUpdateContent();
content.hasRead = hasRead;
}
private static class NotificationUpdateContent{
@SerializedName("read")
private int hasRead;
}
}
......@@ -16,6 +16,7 @@ import br.ufpr.c3sl.agendador.agendador.models.FormFilters;
import br.ufpr.c3sl.agendador.agendador.models.FullDependent;
import br.ufpr.c3sl.agendador.agendador.models.Notification;
import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn;
import br.ufpr.c3sl.agendador.agendador.models.NotificationUpdate;
import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation;
import br.ufpr.c3sl.agendador.agendador.models.ScheduleInfo;
import br.ufpr.c3sl.agendador.agendador.models.ScheduleNote;
......@@ -27,6 +28,7 @@ import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.PATCH;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
......@@ -102,4 +104,7 @@ public interface ApiEndpoints {
@GET("notifications?permission=citizen")
Call<List<NotificationReturn>> requestNotifications();
@PATCH("notifications/{notification_id}?permission=citizen")
Call<NotificationReturn> requestUpdateNotification(@Path("notification_id") long notificationId,@Body NotificationUpdate notification);
}
\ No newline at end of file
......@@ -20,6 +20,7 @@ import br.ufpr.c3sl.agendador.agendador.LoginActivity;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
import br.ufpr.c3sl.agendador.agendador.helpers.Utils;
import br.ufpr.c3sl.agendador.agendador.models.Notification;
import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn;
import br.ufpr.c3sl.agendador.agendador.services.notification.LocalNotificationManager;
import br.ufpr.c3sl.agendador.agendador.services.notification.NotificationReceiver;
import okhttp3.Headers;
......@@ -83,14 +84,14 @@ public abstract class BasePresenter<V> {
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
dispatcher.cancel(Utils.SERVICE_UPDATE_IMAGE);
dispatcher.cancel(Utils.NOTIFICATION_UPDATE_SERVICE);
dispatcher.cancel(Utils.NOTIFICATION_UPDATE_LIST_SERVICE);
if(osb == null)
osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);
Gson gson = new Gson();
List<Notification> notificationList = LocalNotificationManager.getList(osb, gson);
List<NotificationReturn> notificationList = LocalNotificationManager.getList(osb, gson);
Intent intent = new Intent(context, NotificationReceiver.class);
intent.setAction(Utils.ACTION_SHOW_NOTIFICATION);
......@@ -99,10 +100,10 @@ public abstract class BasePresenter<V> {
AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE);
for(Notification n : notificationList){
for(NotificationReturn n : notificationList){
pendingIntent = PendingIntent.getBroadcast(context,
LocalNotificationManager.NOTIFICATION_REMINDER_REQUEST_CODE + (int) n.scheduleId, intent,
LocalNotificationManager.NOTIFICATION_REMINDER_REQUEST_CODE + n.scheduleId.intValue(), intent,
PendingIntent.FLAG_CANCEL_CURRENT);
if(am != null){
......
......@@ -113,7 +113,6 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm
final ApiEndpoints service = ApiUtils.request(header);
final Call<NotificationReturn> listCall = service.requestCreateNotification(notification);
scheduleNotificationJob(notification);
scheduleConfirmationPresenter.view().setProgressBar(true);
listCall.enqueue(new Callback<NotificationReturn>() {
......@@ -121,14 +120,13 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm
public void onResponse(Call<NotificationReturn> call, Response<NotificationReturn> response) {
Headers headers = response.headers();
int status = response.code();
Log.d("Agendador", "Header do create notification:" + headers.get(Utils.ACCESS_TOKEN));
updateHeaders(headers);
switch (status) {
case 201:
Log.d("Server response", this.getClass().getName() + ": 200 - Sucess!");
scheduleConfirmationPresenter.view().setProgressBar(false);
scheduleConfirmationPresenter.view().returnHome();
LocalNotificationManager.createLocalNotification(context, notification, osb, new Gson());
LocalNotificationManager.createLocalNotification(context, response.body(), osb, new Gson());
break;
default:
Log.e("Server response", this.getClass().getName() + ": ERRO:" + status + " na criação de uma notificação.");
......
......@@ -19,7 +19,7 @@ import java.util.Locale;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
import br.ufpr.c3sl.agendador.agendador.helpers.Utils;
import br.ufpr.c3sl.agendador.agendador.models.Notification;
import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn;
import static android.content.Context.ALARM_SERVICE;
......@@ -32,27 +32,25 @@ import static android.content.Context.ALARM_SERVICE;
public abstract class LocalNotificationManager {
public static final int NOTIFICATION_REMINDER_REQUEST_CODE = 0x27;
public static void createLocalNotification(Context context, Notification notification, ObscuredSharedPreferences osb, Gson gson){
Log.d("Agendador", "Criando notificação local...");
public synchronized static void createLocalNotification(Context context, NotificationReturn notification, ObscuredSharedPreferences osb, Gson gson){
addNotification(notification, osb, gson);
SimpleDateFormat sdfServer = new SimpleDateFormat(Utils.SERVER_FORMAT, Locale.getDefault());
Calendar calendar = Calendar.getInstance();
try{
calendar.setTime(sdfServer.parse(notification.reminderTime));
setReminder(context, calendar, (int) notification.scheduleId);
setReminder(context, calendar, notification.scheduleId.intValue());
}catch (ParseException ignored){
Log.e("Agendador", "Erro ao parsear data, para criar notificação local.");
Log.e("Notificacao", "Erro ao parsear data, para criar notificação local.");
ignored.printStackTrace();
}
}
public static void setReminder(Context context, Calendar calendar, int scheduleId){
public synchronized static void setReminder(Context context, Calendar calendar, int scheduleId){
Intent intent = new Intent(context, NotificationReceiver.class);
intent.setAction(Utils.ACTION_SHOW_NOTIFICATION);
......@@ -69,60 +67,65 @@ public abstract class LocalNotificationManager {
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
Log.d("Agendador", "Alarme registrado para o agendamento " + scheduleId + " .");
Log.d("Notificacao", "Alarme registrado para o agendamento " + scheduleId + " .");
}
else{
Log.d("Agendador", "Objeto do Alarm Manager NULL.");
Log.d("Notificacao", "Objeto do Alarm Manager NULL.");
}
}
private static void addNotification(Notification notification, ObscuredSharedPreferences osb, Gson gson){
//Retrieve the values
String jsonList = osb.getString(Utils.NOTIFICATION_LIST, "");
List<Notification> notifications = gson.fromJson(jsonList, new TypeToken<List<Notification>>(){}.getType());
if(notifications == null)
notifications = new ArrayList<>();
notifications.add(notification);
jsonList = gson.toJson(notifications);
private synchronized static void addNotification(NotificationReturn notification, ObscuredSharedPreferences osb, Gson gson){
Log.d("Agendador", "add notification:" + jsonList);
synchronized (LocalNotificationManager.class) {
//Retrieve the values
String jsonList = osb.getString(Utils.NOTIFICATION_LIST, "");
List<NotificationReturn> notifications = gson.fromJson(jsonList, new TypeToken<List<NotificationReturn>>() {
}.getType());
if (notifications == null)
notifications = new ArrayList<>();
notifications.add(notification);
jsonList = gson.toJson(notifications);
osb.edit().putString(Utils.NOTIFICATION_LIST, jsonList).commit();
osb.edit().putString(Utils.NOTIFICATION_LIST, jsonList).commit();
}
}
// TODO: 15/12/17 Testar o retorno da lista.
public static List<Notification> getList(ObscuredSharedPreferences osb, Gson gson){
String jsonList = osb.getString(Utils.NOTIFICATION_LIST, "");
List<Notification> notifications = gson.fromJson(jsonList, new TypeToken<List<Notification>>(){}.getType());
return notifications == null ? new ArrayList<Notification>() : notifications;
public synchronized static List<NotificationReturn> getList(ObscuredSharedPreferences osb, Gson gson){
synchronized (LocalNotificationManager.class) {
String jsonList = osb.getString(Utils.NOTIFICATION_LIST, "");
List<NotificationReturn> notifications = gson.fromJson(jsonList, new TypeToken<List<NotificationReturn>>() {
}.getType());
return notifications == null ? new ArrayList<NotificationReturn>() : notifications;
}
}
// TODO: 15/12/17 Testar o remove.
public static void removeNotification(long scheduleId, ObscuredSharedPreferences osb, Gson gson){
//Retrieve the values
String jsonList = osb.getString(Utils.NOTIFICATION_LIST, "");
List<Notification> notifications = gson.fromJson(jsonList, new TypeToken<List<Notification>>(){}.getType());
for(Notification n : notifications) {
if (n.scheduleId == scheduleId){
notifications.remove(n);
break;
public synchronized static void removeNotification(NotificationReturn notification, ObscuredSharedPreferences osb, Gson gson){
synchronized (LocalNotificationManager.class) {
//Retrieve the values
String jsonList = osb.getString(Utils.NOTIFICATION_LIST, "");
List<NotificationReturn> notifications = gson.fromJson(jsonList, new TypeToken<List<NotificationReturn>>() {
}.getType());
for (NotificationReturn n : notifications) {
if (n.notificationId == notification.notificationId) {
notifications.remove(n);
break;
}
}
}
jsonList = gson.toJson(notifications);
Log.d("Agendador", "remove notification:" + jsonList);
jsonList = gson.toJson(notifications);
osb.edit().putString(Utils.NOTIFICATION_LIST, jsonList).commit();
osb.edit().putString(Utils.NOTIFICATION_LIST, jsonList).commit();
}
}
}
......@@ -32,7 +32,7 @@ public class NotificationCreateService extends JobService {
@Override
public boolean onStartJob(final JobParameters job) {
Log.v("AGNDDR-NotifiCreate", "Rodando " + NotificationCreateService.class.getName());
Log.v("Notificacao", "Rodando " + NotificationCreateService.class.getName());
new Thread(new Runnable() {
public void run() {
......@@ -50,7 +50,7 @@ public class NotificationCreateService extends JobService {
if (extras != null) {
notification = new Gson().fromJson(extras.getString(Utils.NOTIFICATION), Notification.class);
} else {
Log.e("AGNDDR-NotifiCreate", "Job não recebeu os extras.");
Log.e("Notificacao", "Job não recebeu os extras.");
jobFinished(job, true);
}
......@@ -80,7 +80,7 @@ public class NotificationCreateService extends JobService {
case 200:
case 201:
Log.d("Server response", getClass().getName() + ": 200 - Sucesso!");
LocalNotificationManager.createLocalNotification(getApplicationContext(), notification, osb, new Gson());
LocalNotificationManager.createLocalNotification(getApplicationContext(), response.body(), osb, new Gson());
jobFinished(job, false);
break;
default:
......
package br.ufpr.c3sl.agendador.agendador.services.notification;
import android.content.Context;
import android.util.Log;
import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService;
import com.google.gson.Gson;
import java.util.HashMap;
import java.util.Map;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
import br.ufpr.c3sl.agendador.agendador.helpers.Utils;
import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn;
import br.ufpr.c3sl.agendador.agendador.models.NotificationUpdate;
import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints;
import br.ufpr.c3sl.agendador.agendador.network.ApiUtils;
import okhttp3.Headers;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Created by Lucas Braz Cunha on 22/01/18.
*
*
* Service to update back-end's notification, now that user has been notified.
*/
public class NotificationReadService extends JobService {
/**
* The entry point to your Job. Implementations should offload work to another thread of
* execution as soon as possible.
*
*/
@Override
public boolean onStartJob(final JobParameters job) {
new Thread(new Runnable() {
public void run() {
Log.v("Notificacao", "Rodando " + NotificationReadService.class.getName());
Map<String, String> header = new HashMap<>();
ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(getBaseContext(), "Agendador", Context.MODE_PRIVATE);
header.put("Content-Type", "application/json");
header.put(Utils.ACCESS_TOKEN, osb.getString(Utils.ACCESS_TOKEN, null));
header.put(Utils.CLIENT, osb.getString(Utils.CLIENT, null));
header.put(Utils.UID, osb.getString(Utils.UID, null));
requestNotificationRead(header, job, osb);
}
}).start();
return true;
}
private void requestNotificationRead(final Map<String, String> header, final JobParameters job, final ObscuredSharedPreferences osb){
final ApiEndpoints service = ApiUtils.request(header);
if(job.getExtras() == null){
Log.d("Notificacao", "Job 'extras' está vazio.");
jobFinished(job, false);
return;
}
String notificationJson = job.getExtras().getString(Utils.NOTIFICATION);
final NotificationReturn notificationReturn = new Gson().fromJson(notificationJson, NotificationReturn.class);
if(notificationReturn == null){
Log.d("Notificacao", "Conteudo para atualizar está vazio.");
jobFinished(job, false);
return;
}
NotificationUpdate notificationUpdate = new NotificationUpdate(1);
Call<NotificationReturn> listCall = service.requestUpdateNotification(notificationReturn.notificationId, notificationUpdate);
listCall.enqueue(new Callback<NotificationReturn>() {
@Override
public void onResponse(Call<NotificationReturn> call, Response<NotificationReturn> response) {
Headers headers = response.headers();
int status = response.code();
updateHeaders(headers, osb);
switch (status) {
case 200:
case 201:
Log.d("Server response", getClass().getName() + ": 200 - Sucesso!");
LocalNotificationManager.removeNotification(notificationReturn, osb, new Gson());
jobFinished(job, false);
break;
default:
Log.e("Server response", getClass().getName() + ": ERRO:" + status);
jobFinished(job, true);
break;
}
}
@Override
public void onFailure(Call<NotificationReturn> call, Throwable t) {
Log.e("Server response", getClass().getName() + ": Requisição falhou!!");
t.printStackTrace();
jobFinished(job, true);
}
});
}
private void updateHeaders(Headers headers, ObscuredSharedPreferences osb){
if (headers.get(Utils.ACCESS_TOKEN) != null)
osb.edit().putString(Utils.ACCESS_TOKEN, headers.get(Utils.ACCESS_TOKEN)).apply();
if (headers.get(Utils.CLIENT) != null)
osb.edit().putString(Utils.CLIENT, headers.get(Utils.CLIENT)).apply();
if (headers.get(Utils.UID) != null)
osb.edit().putString(Utils.UID, headers.get(Utils.UID)).apply();
if (headers.get(Utils.EXPIRY) != null)
osb.edit().putString(Utils.EXPIRY, headers.get(Utils.EXPIRY)).apply();
}
/**
* Called when the scheduling engine has decided to interrupt the execution of a running job,
* most likely because the runtime constraints associated with the job are no longer satisfied.
* The job must stop execution.
*
*/
@Override
public boolean onStopJob(JobParameters job) {
return false;
}
}
......@@ -6,19 +6,37 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import com.firebase.jobdispatcher.Constraint;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver;
import com.firebase.jobdispatcher.Job;
import com.firebase.jobdispatcher.Lifetime;
import com.firebase.jobdispatcher.RetryStrategy;
import com.firebase.jobdispatcher.Trigger;
import com.google.gson.Gson;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import br.ufpr.c3sl.agendador.agendador.R;
import br.ufpr.c3sl.agendador.agendador.ScheduleInfoActivity;
import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences;
import br.ufpr.c3sl.agendador.agendador.helpers.Utils;
import br.ufpr.c3sl.agendador.agendador.models.Notification;
import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn;
import br.ufpr.c3sl.agendador.agendador.models.NotificationUpdate;
import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints;
import br.ufpr.c3sl.agendador.agendador.network.ApiUtils;
import okhttp3.Headers;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static android.content.Context.NOTIFICATION_SERVICE;
......@@ -33,43 +51,135 @@ public class NotificationReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
if(intent.getAction() != null && intent.getAction().equals(Utils.ACTION_SHOW_NOTIFICATION)){
int id = intent.getIntExtra(Utils.ID, -1);
Log.d("Agendador", "Estou no "+ NotificationReceiver.class.getName() +"! Notificação de id "+ id);
Log.d("Notificacao", "Estou no "+ NotificationReceiver.class.getName() +"! Notificação de id "+ id);
ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);
Notification content = null;
NotificationReturn content = null;
Gson gson = new Gson();
List<Notification> notifications = LocalNotificationManager.getList(osb, gson);
for(Notification n : notifications){
List<NotificationReturn> notifications = LocalNotificationManager.getList(osb, gson);
for(NotificationReturn n : notifications){
if(n.scheduleId == id){
content = n;
break;
}
}
// TODO: 19/01/18 só remover a notificação depois de enviar para o servidor que ela foi mostrada.
LocalNotificationManager.removeNotification(id, osb, gson);
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(NOTIFICATION_SERVICE);
if(content == null || notificationManager == null){
Log.e("Agendador", "Erro: notificação não encontrada, ou notification manager null");
return;
}
if(content == null){