From ca20ff24924d8834e6aac44978f1df3228b8991d Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Fri, 24 Nov 2017 19:47:28 -0200 Subject: [PATCH 1/9] AGILE#256: [WIP] Create notification on schedule Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- app/src/main/AndroidManifest.xml | 11 +- .../ScheduleConfirmationActivity.java | 138 +++++- .../agendador/SchedulesHistoryActivity.java | 9 +- .../agendador/SchedulingActivity.java | 6 +- .../agendador/agendador/helpers/Utils.java | 8 +- ...lterListener.java => SpinnerListener.java} | 13 +- .../SectorSpinnerListener.java | 3 +- .../ServicePlaceSpinnerListener.java | 5 +- .../ServiceTypeSpinnerListener.java | 6 +- .../agendador/models/Notification.java | 79 ++++ .../agendador/network/ApiEndpoints.java | 5 +- .../agendador/agendador/network/ApiUtils.java | 4 +- .../ScheduleConfirmationPresenter.java | 100 +++- .../services/ImageUpdateService.java | 5 +- .../services/NotificationCreateService.java | 104 +++++ .../views/ScheduleConfirmationView.java | 6 +- .../agendador/views/SpinnerActivity.java | 10 + .../layout/content_schedule_confirmation.xml | 439 +++++++++++------- app/src/main/res/values/integer.xml | 13 + app/src/main/res/values/strings.xml | 18 + 20 files changed, 770 insertions(+), 212 deletions(-) rename app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/{schedulesHistory/FilterListener.java => SpinnerListener.java} (62%) rename app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/{ => scheduling}/SectorSpinnerListener.java (96%) rename app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/{ => scheduling}/ServicePlaceSpinnerListener.java (96%) rename app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/{ => scheduling}/ServiceTypeSpinnerListener.java (96%) create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/NotificationCreateService.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/SpinnerActivity.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 070cae3..2497fce 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -47,6 +47,15 @@ </intent-filter> </service> + <service + android:name=".services.NotificationCreateService" + android:exported="false" + android:permission="android.permission.BIND_JOB_SERVICE"> + <intent-filter> + <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" /> + </intent-filter> + </service> + <activity android:name=".TermActivity" /> <activity android:name=".SchedulingActivity"/> <activity android:name=".CitizenListActivity" /> @@ -57,7 +66,7 @@ <activity android:name=".RetrievalFailureActivity" /> <activity android:name=".RetrievalSuccessActivity" /> <activity android:name=".SchedulesHistoryActivity" /> - <activity android:name=".ScheduleInfoActivity"></activity> + <activity android:name=".ScheduleInfoActivity" /> </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java index ff28cb4..d08497d 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java @@ -6,6 +6,7 @@ import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.graphics.Color; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; @@ -19,22 +20,30 @@ import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; +import android.widget.RadioButton; +import android.widget.Spinner; import android.widget.TextView; +import android.widget.Toast; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Locale; import br.ufpr.c3sl.agendador.agendador.helpers.ConnectionErrorDialog; +import br.ufpr.c3sl.agendador.agendador.helpers.DateValidator; import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; import br.ufpr.c3sl.agendador.agendador.helpers.UserImgHelper; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; +import br.ufpr.c3sl.agendador.agendador.models.CheckSchedules; import br.ufpr.c3sl.agendador.agendador.models.CitizenCompact; +import br.ufpr.c3sl.agendador.agendador.models.Notification; import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; -import br.ufpr.c3sl.agendador.agendador.models.UserOutput; import br.ufpr.c3sl.agendador.agendador.presenters.PresenterManager; import br.ufpr.c3sl.agendador.agendador.presenters.ScheduleConfirmationPresenter; import br.ufpr.c3sl.agendador.agendador.views.ScheduleConfirmationView; @@ -58,22 +67,27 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S private ProgressBar pb_scheduleConfirmation; + private EditText et_email; + + private TextView tv_email_warning; + private Button bt_schedule, bt_back; + private String[] notificationTime; + + private static String SPINNER_POS = "spinner_position"; + + private Spinner sp_notification; + private static final String EXIT_CONFIRMATION_DIALOG_TAG = "exit_dialog"; + private RadioButton rb_yes, rb_no; + private long id; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if(savedInstanceState == null){ - scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(getBaseContext()); - }else{ - scheduleConfirmationPresenter = PresenterManager.getInstance().restorePresenter(savedInstanceState); - if(scheduleConfirmationPresenter == null) - scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(this); - } setContentView(R.layout.activity_schedule_confirmation); Bundle bundle = getIntent().getBundleExtra(Utils.SCHEDULE_BUNDLE); @@ -146,6 +160,15 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S navigationView.setNavigationItemSelectedListener(this); + + notificationTime = getResources().getStringArray(R.array.notification_time); + + sp_notification = (Spinner) findViewById(R.id.spnr_schedule_time); + + sp_notification.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, notificationTime)); + + sp_notification.setSelection(1, true); + pb_scheduleConfirmation = (ProgressBar) findViewById(R.id.pb_schedule_confirmation); TextView tv_citizen = (TextView) findViewById(R.id.tv_schedule_citizen_content); @@ -154,7 +177,8 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S TextView tv_type = (TextView) findViewById(R.id.tv_schedule_type_content); TextView tv_schedule = (TextView) findViewById(R.id.tv_schedule_date_content); TextView tv_street = (TextView) findViewById(R.id.tv_schedule_street_content); - + et_email = (EditText) findViewById(R.id.et_schedule_email); + tv_email_warning = (TextView) findViewById(R.id.tv_schedule_email_warning); tv_sector.setText(sectorName); tv_citizen.setText(citizen.getName()); @@ -172,9 +196,58 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S bt_schedule.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - scheduleConfirmationPresenter.onScheduleClicked(scheduleConfirmation, citizen); - bt_schedule.setEnabled(false); - bt_back.setEnabled(false); + boolean schedule = true; + if(rb_yes.isChecked()){ + if(!DateValidator.isValidEmail(et_email.getText().toString())){ + Toast.makeText(getBaseContext(), getResources().getString(R.string.not_valid_email), Toast.LENGTH_SHORT).show(); + schedule = false; + tv_email_warning.setVisibility(View.VISIBLE); + }else{ + tv_email_warning.setVisibility(View.INVISIBLE); + } + + } + + if(schedule){ + + scheduleConfirmationPresenter.onScheduleClicked(scheduleConfirmation, citizen); + bt_schedule.setEnabled(false); + bt_back.setEnabled(false); + + } + + + } + }); + + final TextView tv_email = (TextView) findViewById(R.id.tv_schedule_email); + + rb_yes = (RadioButton) findViewById(R.id.rb_notify_email_yes); + + rb_yes.setChecked(true); + + rb_no = (RadioButton) findViewById(R.id.rb_notify_email_no); + + rb_yes.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + rb_no.setChecked(false); + et_email.setEnabled(true); + tv_email.setTextColor(Color.BLACK); + if(sp_notification.getSelectedItemPosition() == 0){ + sp_notification.setSelection(1, true); + } + } + }); + + rb_no.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + rb_yes.setChecked(false); + et_email.setEnabled(false); + et_email.setText(""); + tv_email.setTextColor(Color.GRAY); + tv_email_warning.setVisibility(View.INVISIBLE); } }); @@ -184,6 +257,15 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S onBackPressed(); } }); + + if(savedInstanceState == null){ + scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(getBaseContext()); + }else{ + sp_notification.setSelection( savedInstanceState.getInt(SPINNER_POS, 1), true); + scheduleConfirmationPresenter = PresenterManager.getInstance().restorePresenter(savedInstanceState); + if(scheduleConfirmationPresenter == null) + scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(this); + } } @Override @@ -202,6 +284,7 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S @Override public void onSaveInstanceState(Bundle outState) { PresenterManager.getInstance().savePresenter(scheduleConfirmationPresenter, outState); + outState.putInt(SPINNER_POS, sp_notification.getSelectedItemPosition()); super.onSaveInstanceState(outState); } @@ -279,7 +362,36 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S } } - public void onSuccess(){ + @Override + public void onSuccess(ScheduleConfirmation schedule){ + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ", Locale.getDefault()); + /* + * Position zero is "don't notify" + */ + int reminderTimeArray[] = getResources().getIntArray(R.array.notification_time_int); + + if(sp_notification.getSelectedItemPosition() != 0 ){ + Notification notification = new Notification(); + notification.scheduleId = schedule.getId(); + notification.emailSent = false; + notification.description = "a"; + //reminderTime*1000 to transform milliseconds to minutes. + notification.reminderTime = sdf.format(schedule.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()]*1000)); + + if(rb_yes.isChecked()){ + notification.emailAddres = et_email.getText().toString(); + } + + scheduleConfirmationPresenter.createNotification(notification); + }else{ + returnHome(); + } + + } + + @Override + public void returnHome(){ Intent intent = new Intent(ScheduleConfirmationActivity.this, HomeActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); Bundle bundle = new Bundle(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java index c580f35..12e6ecb 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java @@ -39,7 +39,7 @@ import br.ufpr.c3sl.agendador.agendador.helpers.UserImgHelper; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; import br.ufpr.c3sl.agendador.agendador.helpers.adapters.HintAdapter; import br.ufpr.c3sl.agendador.agendador.helpers.adapters.SchedulesExpandableListAdapter; -import br.ufpr.c3sl.agendador.agendador.helpers.listeners.schedulesHistory.FilterListener; +import br.ufpr.c3sl.agendador.agendador.helpers.listeners.SpinnerListener; import br.ufpr.c3sl.agendador.agendador.models.CheckSchedules; import br.ufpr.c3sl.agendador.agendador.models.FormFilters; import br.ufpr.c3sl.agendador.agendador.models.ServicePlace; @@ -47,10 +47,10 @@ import br.ufpr.c3sl.agendador.agendador.models.ServiceType; import br.ufpr.c3sl.agendador.agendador.presenters.PresenterManager; import br.ufpr.c3sl.agendador.agendador.presenters.SchedulesHistoryPresenter; import br.ufpr.c3sl.agendador.agendador.views.SchedulesHistoryView; +import br.ufpr.c3sl.agendador.agendador.views.SpinnerActivity; - -public class SchedulesHistoryActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, SchedulesHistoryView { +public class SchedulesHistoryActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, SchedulesHistoryView, SpinnerActivity { private NavigationView navigationView; private MenuBuilder menuBuilder; @@ -65,7 +65,6 @@ public class SchedulesHistoryActivity extends AppCompatActivity implements Navig private FormFilters filters; private long[] sectorsIdArray, serviceTypesIdArray, servicePlacesIdArray, situationIdArray; private Button bt_search, bt_clear; - private FilterListener filterListener; private static final String EXIT_CONFIRMATION_DIALOG_TAG = "exit_dialog"; private static final String SPINNER_SECTOR = "spinner_setor"; private static final String SPINNER_TYPE = "spinner_type"; @@ -242,7 +241,7 @@ public class SchedulesHistoryActivity extends AppCompatActivity implements Navig } }); - filterListener = new FilterListener(this); + SpinnerListener filterListener = new SpinnerListener(this); sp_sector.setOnItemSelectedListener(filterListener); sp_sector.setOnTouchListener(filterListener); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java index 363badc..2df2714 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java @@ -49,9 +49,9 @@ import br.ufpr.c3sl.agendador.agendador.helpers.adapters.HintAdapter; import br.ufpr.c3sl.agendador.agendador.helpers.adapters.HintEnableAdapter; import br.ufpr.c3sl.agendador.agendador.helpers.decorators.NotAvailableDecorator; import br.ufpr.c3sl.agendador.agendador.helpers.decorators.SchedulesDecorator; -import br.ufpr.c3sl.agendador.agendador.helpers.listeners.SectorSpinnerListener; -import br.ufpr.c3sl.agendador.agendador.helpers.listeners.ServicePlaceSpinnerListener; -import br.ufpr.c3sl.agendador.agendador.helpers.listeners.ServiceTypeSpinnerListener; +import br.ufpr.c3sl.agendador.agendador.helpers.listeners.scheduling.SectorSpinnerListener; +import br.ufpr.c3sl.agendador.agendador.helpers.listeners.scheduling.ServicePlaceSpinnerListener; +import br.ufpr.c3sl.agendador.agendador.helpers.listeners.scheduling.ServiceTypeSpinnerListener; import br.ufpr.c3sl.agendador.agendador.models.CitizenCompact; import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; import br.ufpr.c3sl.agendador.agendador.models.SectorInput; diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java index 9a1db72..5e3f815 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java @@ -108,6 +108,8 @@ public abstract class Utils { public static final String REQUEST_FILTER_PLACE = "q[service_place_id]"; public static final String REQUEST_FILTER_SITUATION = "q[situation_id]"; public static final String SIZE_LARGE = "large"; + public static final String NOTIFICATION = "notification"; + public static final String NOTIFICATION_SERVICE = "br.c3sl.ufpr.notification_service"; public static int getPixelValue(int dp, Context context) { Resources resources = context.getResources(); @@ -170,9 +172,9 @@ public abstract class Utils { String s = calendar.get(Calendar.YEAR) + ""; tv_calendarHeaderYear.setText(s); - - tv_calendarHeaderDayHour.setText(days_short[calendar.get(Calendar.DAY_OF_WEEK) - 1] + ", " + - months_short[calendar.get(Calendar.MONTH)] + " " + calendar.get(Calendar.DAY_OF_MONTH)); + String text = days_short[calendar.get(Calendar.DAY_OF_WEEK) - 1] + ", " + + months_short[calendar.get(Calendar.MONTH)] + " " + calendar.get(Calendar.DAY_OF_MONTH); + tv_calendarHeaderDayHour.setText(text); } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/schedulesHistory/FilterListener.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerListener.java similarity index 62% rename from app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/schedulesHistory/FilterListener.java rename to app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerListener.java index c577ea3..f3d9d4e 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/schedulesHistory/FilterListener.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerListener.java @@ -1,21 +1,21 @@ -package br.ufpr.c3sl.agendador.agendador.helpers.listeners.schedulesHistory; +package br.ufpr.c3sl.agendador.agendador.helpers.listeners; import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; -import br.ufpr.c3sl.agendador.agendador.views.SchedulesHistoryView; +import br.ufpr.c3sl.agendador.agendador.views.SpinnerActivity; /** - * Created by Lucas B. Cunha on 30/10/17. + * Created by Lucas Braz Cunha on 22/11/17. */ -public class FilterListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener { +public class SpinnerListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener { private boolean userSelect; - private SchedulesHistoryView activity; + private SpinnerActivity activity; - public FilterListener(SchedulesHistoryView activity) { + public SpinnerListener(SpinnerActivity activity) { this.activity = activity; this.userSelect = false; } @@ -23,6 +23,7 @@ public class FilterListener implements AdapterView.OnItemSelectedListener, View. @Override public boolean onTouch(View v, MotionEvent event) { userSelect = true; + v.performClick(); return false; } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SectorSpinnerListener.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/SectorSpinnerListener.java similarity index 96% rename from app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SectorSpinnerListener.java rename to app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/SectorSpinnerListener.java index 245aa1f..6132923 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SectorSpinnerListener.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/SectorSpinnerListener.java @@ -1,4 +1,4 @@ -package br.ufpr.c3sl.agendador.agendador.helpers.listeners; +package br.ufpr.c3sl.agendador.agendador.helpers.listeners.scheduling; import android.view.MotionEvent; import android.view.View; @@ -53,6 +53,7 @@ public class SectorSpinnerListener implements AdapterView.OnItemSelectedListener @Override public boolean onTouch(View v, MotionEvent event) { userSelect = true; + v.performClick(); return false; } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/ServicePlaceSpinnerListener.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/ServicePlaceSpinnerListener.java similarity index 96% rename from app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/ServicePlaceSpinnerListener.java rename to app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/ServicePlaceSpinnerListener.java index 0733222..9252832 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/ServicePlaceSpinnerListener.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/ServicePlaceSpinnerListener.java @@ -1,4 +1,4 @@ -package br.ufpr.c3sl.agendador.agendador.helpers.listeners; +package br.ufpr.c3sl.agendador.agendador.helpers.listeners.scheduling; import android.view.MotionEvent; import android.view.View; @@ -48,12 +48,13 @@ public class ServicePlaceSpinnerListener implements AdapterView.OnItemSelectedLi @Override public boolean onTouch(View v, MotionEvent event) { userSelect = true; + v.performClick(); return false; } @Override public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { - if (userSelect && servicePlaces != null && servicePlaces.size() > 0 ) { + if (userSelect && servicePlaces != null && servicePlaces.size() > 0) { mcv.setSelectionMode(MaterialCalendarView.SELECTION_MODE_SINGLE); //if the position is the hint. diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/ServiceTypeSpinnerListener.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/ServiceTypeSpinnerListener.java similarity index 96% rename from app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/ServiceTypeSpinnerListener.java rename to app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/ServiceTypeSpinnerListener.java index 6d69eee..1601455 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/ServiceTypeSpinnerListener.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/scheduling/ServiceTypeSpinnerListener.java @@ -1,6 +1,5 @@ -package br.ufpr.c3sl.agendador.agendador.helpers.listeners; +package br.ufpr.c3sl.agendador.agendador.helpers.listeners.scheduling; -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; @@ -53,12 +52,13 @@ public class ServiceTypeSpinnerListener implements AdapterView.OnItemSelectedLis @Override public boolean onTouch(View v, MotionEvent event) { userSelect = true; + v.performClick(); return false; } @Override public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { - if (userSelect && serviceTypes != null && serviceTypes.size() > 0 ) { + if (userSelect && serviceTypes != null && serviceTypes.size() > 0) { presenter.requestAvailableSchedules(serviceTypes.get(pos).getId()); Utils.updateCalendarHeaderDate(mcv, tv_calendarHeaderYear, tv_calendarHeaderDayHour, days_short, months_short, null); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java new file mode 100644 index 0000000..1811b3c --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java @@ -0,0 +1,79 @@ +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 24/11/17. + */ + +public class Notification implements Parcelable{ + + @SerializedName("schedule_id") + public long scheduleId; + + @SerializedName("reminder_time") + public String reminderTime; + + @SerializedName("read") + public boolean hasRead; + + @SerializedName("content") + public String description; + + @SerializedName("reminder_email") + public String emailAddres; + + @SerializedName("email_sent") + public boolean emailSent; + + + public Notification() { + } + + /**reads back fields IN THE ORDER they were written */ + private Notification(Parcel pc){ + scheduleId = pc.readLong(); + reminderTime = pc.readString(); + hasRead = pc.readByte() != 0; + description = pc.readString(); + emailAddres = pc.readString(); + emailSent = pc.readByte() != 0; + } + + /** Static field used to regenerate object, individually or as arrays */ + public static final Parcelable.Creator<Notification> CREATOR = new Parcelable.Creator<Notification>() { + public Notification createFromParcel(Parcel pc) { + return new Notification(pc); + } + public Notification[] newArray(int size) { + return new Notification[size]; + } + }; + + /** + * Flatten this object in to a Parcel. + * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(scheduleId); + dest.writeString(reminderTime); + dest.writeByte((byte) (hasRead ? 1 : 0)); + dest.writeString(description); + dest.writeString(emailAddres); + dest.writeByte((byte) (emailSent ? 1 : 0)); + } + + @Override + public int describeContents() { + return 0; + } + + +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java index e2a8ed7..1d1aab1 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java @@ -14,6 +14,7 @@ import br.ufpr.c3sl.agendador.agendador.models.Dependent; import br.ufpr.c3sl.agendador.agendador.models.DependentCreation; 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.ScheduleConfirmation; import br.ufpr.c3sl.agendador.agendador.models.ScheduleNote; import br.ufpr.c3sl.agendador.agendador.models.SectorInput; @@ -87,9 +88,11 @@ public interface ApiEndpoints { @GET("schedules?permission=citizen") Call<CheckSchedules> requestSchedulesHistory(@QueryMap Map<String, String> options); - @GET("forms/schedule_history?permission=citizen") Call<FormFilters> requestCitizenSectors(); + @POST("notifications?permission=2") + Call<ScheduleConfirmation> requestCreateNotification(@Body Notification notification); + } \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java index 3cc8490..14ec54a 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java @@ -14,8 +14,8 @@ import retrofit2.converter.gson.GsonConverterFactory; */ public abstract class ApiUtils { -// public static final String BASE_URL = "http://10.0.2.2:3000/v1/"; - public static final String BASE_URL = "http://newcastle.c3sl.ufpr.br/develop/v1/"; + public static final String BASE_URL = "http://10.0.2.2:3000/v1/"; +// public static final String BASE_URL = "http://newcastle.c3sl.ufpr.br/develop/v1/"; public static ApiEndpoints request(final Map<String, String> header) { OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java index 759f804..9ccd9c2 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java @@ -2,10 +2,17 @@ package br.ufpr.c3sl.agendador.agendador.presenters; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.util.Log; +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.Map; @@ -15,11 +22,14 @@ import br.ufpr.c3sl.agendador.agendador.ScheduleConfirmationActivity; import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; import br.ufpr.c3sl.agendador.agendador.models.CitizenCompact; +import br.ufpr.c3sl.agendador.agendador.models.Notification; import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; import br.ufpr.c3sl.agendador.agendador.models.ScheduleNote; import br.ufpr.c3sl.agendador.agendador.models.UserOutput; import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints; import br.ufpr.c3sl.agendador.agendador.network.ApiUtils; +import br.ufpr.c3sl.agendador.agendador.services.ImageUpdateService; +import br.ufpr.c3sl.agendador.agendador.services.NotificationCreateService; import okhttp3.Headers; import retrofit2.Call; import retrofit2.Callback; @@ -33,10 +43,16 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm private ScheduleConfirmationPresenter scheduleConfirmationPresenter; + private FirebaseJobDispatcher dispatcher; + public ScheduleConfirmationPresenter(Context context){ this.context = context; this.scheduleConfirmationPresenter = this; osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE); + + dispatcher = new FirebaseJobDispatcher( + new GooglePlayDriver(context) + ); } @@ -60,14 +76,14 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm public void onResponse(Call<ScheduleConfirmation> call, Response<ScheduleConfirmation> response) { Headers headers = response.headers(); int status = response.code(); - //ScheduleConfirmation confirmationResponse = response.body(); + ScheduleConfirmation confirmationResponse = response.body(); updateHeaders(headers); switch (status) { case 200: Log.d("Server response", this.getClass().getName() + ": 200 - Sucesso!"); scheduleConfirmationPresenter.view().setProgressBar(false); + scheduleConfirmationPresenter.view().onSuccess(confirmationResponse); - scheduleConfirmationPresenter.view().onSuccess(); break; default: Log.e("Server response", this.getClass().getName() + ": ERRO:" + status); @@ -87,6 +103,86 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm } + + public void createNotification(final Notification notification){ + Map<String, String> header = new HashMap<>(); + 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)); + + final ApiEndpoints service = ApiUtils.request(header); + + + // TODO: 24/11/17 arrumar retorno + Call<ScheduleConfirmation> listCall = service.requestCreateNotification(notification); + + scheduleConfirmationPresenter.view().setProgressBar(true); + listCall.enqueue(new Callback<ScheduleConfirmation>() { + + @Override + public void onResponse(Call<ScheduleConfirmation> call, Response<ScheduleConfirmation> response) { + Headers headers = response.headers(); + int status = response.code(); + //ScheduleConfirmation confirmationResponse = response.body(); + updateHeaders(headers); + switch (status) { + case 200: + Log.d("Server response", this.getClass().getName() + ": 200 - Sucess!"); + scheduleConfirmationPresenter.view().setProgressBar(false); + + scheduleConfirmationPresenter.view().returnHome(); + break; + default: + Log.e("Server response", this.getClass().getName() + ": ERRO:" + status + ". Scheduling job"); + scheduleNotificationJob(notification); + scheduleConfirmationPresenter.view().setProgressBar(false); + scheduleConfirmationPresenter.view().returnHome(); + break; + } + } + @Override + public void onFailure(Call<ScheduleConfirmation> call, Throwable t) { + Log.e("Server response", this.getClass().getName() + ": Request Failed, Scheduling job."); + + scheduleNotificationJob(notification); + + scheduleConfirmationPresenter.view().setProgressBar(false); + scheduleConfirmationPresenter.view().returnHome(); + } + }); + + } + + + + private void scheduleNotificationJob(Notification notification){ + Bundle extras = new Bundle(); + + Gson g = new Gson(); + String json = g.toJson(notification); + + extras.putString(Utils.NOTIFICATION, json); + + Job job = dispatcher.newJobBuilder() + .setService(NotificationCreateService.class) + .setTag(Utils.NOTIFICATION_SERVICE) + //time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600 + .setTrigger(Trigger.executionWindow(0, 3600)) + //will be retried if it fails. + .setRecurring(true) + .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) + .setConstraints( + // only run on network + Constraint.ON_ANY_NETWORK + ) + .setExtras(extras) + //if device is rebooted the job will be restarted + .setLifetime(Lifetime.FOREVER) + .build(); + dispatcher.mustSchedule(job); + } + @Override protected void updateView() {} } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/ImageUpdateService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/ImageUpdateService.java index 660d53e..4a7d303 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/ImageUpdateService.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/ImageUpdateService.java @@ -30,7 +30,6 @@ import retrofit2.Response; public class ImageUpdateService extends JobService { - /** * The entry point to your Job. Implementations should offload work to another thread of * execution as soon as possible. @@ -88,10 +87,10 @@ public class ImageUpdateService extends JobService { break; case 404: //user has no picture on back-end - Log.d("AGNDDR-ImgService", "Job Foi executado e usuário não possui foto"); + Log.d("AGNDDR-ImgService", "Job foi executado e usuário não possui foto"); jobFinished(job, false); default: - Log.d("AGNDDR-ImgService", "Job Foi executado mas recebeu retorno " + status); + Log.d("AGNDDR-ImgService", "Job foi executado mas recebeu retorno " + status); jobFinished(job, true); break; diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/NotificationCreateService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/NotificationCreateService.java new file mode 100644 index 0000000..8169038 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/NotificationCreateService.java @@ -0,0 +1,104 @@ +package br.ufpr.c3sl.agendador.agendador.services; + +import android.content.Context; +import android.os.Bundle; +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.Notification; +import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; +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 24/11/17. + */ + +public class NotificationCreateService extends JobService { + + + @Override + public boolean onStartJob(final JobParameters job) { + Log.v("AGNDDR-NotifiCreate", "Rodando " + NotificationCreateService.class.getName()); + ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(getBaseContext(), "Agendador", Context.MODE_PRIVATE); + final Bundle extras = job.getExtras(); + Map<String, String> header = new HashMap<>(); + + final String uid = osb.getString(Utils.UID, null); + 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.ID, uid); + + Notification notification = null; + + if (extras != null) { + notification = new Gson().fromJson(extras.getString(Utils.NOTIFICATION), Notification.class); + }else{ + Log.e("AGNDDR-NotifiCreate", "Job não recebeu os extras."); + jobFinished(job, true); + } + + ApiEndpoints service = ApiUtils.request(header); + + Call<ScheduleConfirmation> listCall = service.requestCreateNotification(notification); + + listCall.enqueue(new Callback<ScheduleConfirmation>() { + + @Override + public void onResponse(Call<ScheduleConfirmation> call, Response<ScheduleConfirmation> response) { + int status = response.code(); + Headers headers = response.headers(); + ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(getBaseContext(), "Agendador", Context.MODE_PRIVATE); + + 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(); + + switch (status) { + case 200: + + jobFinished(job, false); + break; + default: + Log.v("AGNDDR-NotifiCreate", "Job foi executado mas recebeu retorno " + status); + jobFinished(job, true); + break; + } + + } + + @Override + public void onFailure(Call<ScheduleConfirmation> call, Throwable t) { + Log.v("AGNDDR-NotifiCreate", "Job falhou e será remarcado!!"); + jobFinished(job, true); + } + }); + + + return true; + } + + + @Override + public boolean onStopJob(JobParameters job) { + return true; + } +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java index 930089b..25d0935 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java @@ -1,5 +1,7 @@ package br.ufpr.c3sl.agendador.agendador.views; +import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; + /** * Created by Lucas B. Cunha on 25/07/17. */ @@ -10,8 +12,10 @@ public interface ScheduleConfirmationView { void setProgressBar(boolean enabled); - void onSuccess(); + void onSuccess(ScheduleConfirmation confirmationResponse); void setConnectionError(boolean enabled); + void returnHome(); + } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/SpinnerActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/SpinnerActivity.java new file mode 100644 index 0000000..f8c31cc --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/SpinnerActivity.java @@ -0,0 +1,10 @@ +package br.ufpr.c3sl.agendador.agendador.views; + +/** + * Created by Lucas Braz Cunha on 22/11/17. + */ + +public interface SpinnerActivity { + + void updateSpinners(int id); +} diff --git a/app/src/main/res/layout/content_schedule_confirmation.xml b/app/src/main/res/layout/content_schedule_confirmation.xml index 04ccbdb..d5a2107 100644 --- a/app/src/main/res/layout/content_schedule_confirmation.xml +++ b/app/src/main/res/layout/content_schedule_confirmation.xml @@ -20,222 +20,329 @@ android:typeface="normal" /> - <LinearLayout + <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/tv_scheduling_welcome" - android:orientation="vertical" android:background="@color/colorWhite"> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="24dp" - android:layout_marginTop="24dp" - android:layout_marginBottom="5dp" - android:gravity="center" - android:text="@string/schedule_confirmation_description" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="16sp" - android:textStyle="normal|bold" - android:typeface="normal" /> - - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="14dp" - android:layout_gravity="start" - android:text="@string/schedule_confirmation_title" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="16sp" - android:textStyle="normal|bold" - android:typeface="normal"/> - - <RelativeLayout + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="10dp"> + android:orientation="vertical"> <TextView - android:id="@+id/tv_schedule_citizen" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="14dp" - android:layout_gravity="start" + android:layout_marginStart="24dp" + android:layout_marginTop="24dp" + android:layout_marginBottom="5dp" + android:gravity="center" + android:text="@string/schedule_confirmation_description" android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:text="@string/schedule_confirmation_citizen" android:textSize="16sp" android:textStyle="normal|bold" - android:typeface="normal"/> + android:typeface="normal" /> - <TextView - android:id="@+id/tv_schedule_citizen_content" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="14sp" - android:typeface="normal" - android:layout_marginStart="3dp" - android:layout_alignBaseline="@+id/tv_schedule_citizen" - android:layout_alignBottom="@+id/tv_schedule_citizen" - android:layout_toEndOf="@+id/tv_schedule_citizen" /> <TextView - android:id="@+id/tv_schedule_sector" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginStart="14dp" android:layout_gravity="start" - android:text="@string/schedule_confirmation_sector" + android:text="@string/schedule_confirmation_title" android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textSize="16sp" android:textStyle="normal|bold" - android:typeface="normal" - android:layout_below="@+id/tv_schedule_citizen_content" - android:layout_marginTop="20dp" - android:layout_alignStart="@+id/tv_schedule_citizen" /> + android:typeface="normal"/> - <TextView - android:id="@+id/tv_schedule_sector_content" - android:layout_width="wrap_content" + <RelativeLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="14sp" - android:typeface="normal" - android:layout_marginStart="3dp" - android:layout_alignBaseline="@+id/tv_schedule_sector" - android:layout_alignBottom="@+id/tv_schedule_sector" - android:layout_toEndOf="@+id/tv_schedule_sector"/> + android:layout_marginTop="10dp"> - <TextView - android:id="@+id/tv_schedule_location" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/schedule_confirmation_place" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="16sp" - android:textStyle="normal|bold" - android:typeface="normal" - android:layout_marginTop="15dp" - android:layout_below="@id/tv_schedule_sector_content" - android:layout_alignStart="@+id/tv_schedule_citizen" /> + <TextView + android:id="@+id/tv_schedule_citizen" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="14dp" + android:layout_gravity="start" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:text="@string/schedule_confirmation_citizen" + android:textSize="16sp" + android:textStyle="normal|bold" + android:typeface="normal"/> - <TextView - android:id="@+id/tv_schedule_location_content" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="14sp" - android:typeface="normal" - android:layout_marginStart="3dp" - android:layout_alignBaseline="@+id/tv_schedule_location" - android:layout_alignBottom="@+id/tv_schedule_location" - android:layout_toEndOf="@+id/tv_schedule_location"/> + <TextView + android:id="@+id/tv_schedule_citizen_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="14sp" + android:typeface="normal" + android:layout_marginStart="3dp" + android:layout_alignBaseline="@+id/tv_schedule_citizen" + android:layout_alignBottom="@+id/tv_schedule_citizen" + android:layout_toEndOf="@+id/tv_schedule_citizen" /> + + <TextView + android:id="@+id/tv_schedule_sector" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:text="@string/schedule_confirmation_sector" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="16sp" + android:textStyle="normal|bold" + android:typeface="normal" + android:layout_below="@+id/tv_schedule_citizen_content" + android:layout_marginTop="20dp" + android:layout_alignStart="@+id/tv_schedule_citizen" /> + + <TextView + android:id="@+id/tv_schedule_sector_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="14sp" + android:typeface="normal" + android:layout_marginStart="3dp" + android:layout_alignBaseline="@+id/tv_schedule_sector" + android:layout_alignBottom="@+id/tv_schedule_sector" + android:layout_toEndOf="@+id/tv_schedule_sector"/> + + <TextView + android:id="@+id/tv_schedule_location" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/schedule_confirmation_place" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="16sp" + android:textStyle="normal|bold" + android:typeface="normal" + android:layout_marginTop="15dp" + android:layout_below="@id/tv_schedule_sector_content" + android:layout_alignStart="@+id/tv_schedule_citizen" /> + + <TextView + android:id="@+id/tv_schedule_location_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="14sp" + android:typeface="normal" + android:layout_marginStart="3dp" + android:layout_alignBaseline="@+id/tv_schedule_location" + android:layout_alignBottom="@+id/tv_schedule_location" + android:layout_toEndOf="@+id/tv_schedule_location"/> + + <TextView + android:id="@+id/tv_schedule_type" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/schedule_confirmation_type" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="16sp" + android:textStyle="normal|bold" + android:typeface="normal" + android:layout_marginTop="15dp" + android:layout_below="@id/tv_schedule_location_content" + android:layout_alignStart="@+id/tv_schedule_citizen" /> + + <TextView + android:id="@+id/tv_schedule_type_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="14sp" + android:typeface="normal" + android:layout_marginStart="3dp" + android:layout_alignBaseline="@+id/tv_schedule_type" + android:layout_alignBottom="@+id/tv_schedule_type" + android:layout_toEndOf="@+id/tv_schedule_type"/> + + <TextView + android:id="@+id/tv_schedule_date" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/schedule_confirmation_date" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="16sp" + android:textStyle="normal|bold" + android:typeface="normal" + android:layout_marginTop="15dp" + android:layout_below="@id/tv_schedule_type_content" + android:layout_alignStart="@+id/tv_schedule_citizen"/> + + <TextView + android:id="@+id/tv_schedule_date_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="14sp" + android:typeface="normal" + android:layout_marginStart="3dp" + android:layout_alignBaseline="@+id/tv_schedule_date" + android:layout_alignBottom="@+id/tv_schedule_date" + android:layout_toEndOf="@+id/tv_schedule_date"/> + + <TextView + android:id="@+id/tv_schedule_street" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/schedule_confirmation_street" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="16sp" + android:textStyle="normal|bold" + android:typeface="normal" + android:layout_marginTop="15dp" + android:layout_below="@id/tv_schedule_date_content" + android:layout_alignStart="@+id/tv_schedule_citizen"/> + + <TextView + android:id="@+id/tv_schedule_street_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="14sp" + android:typeface="normal" + android:layout_marginStart="3dp" + android:layout_alignBaseline="@+id/tv_schedule_street" + android:layout_alignBottom="@+id/tv_schedule_street" + android:layout_toEndOf="@+id/tv_schedule_street"/> + + </RelativeLayout> - <TextView - android:id="@+id/tv_schedule_type" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/schedule_confirmation_type" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="16sp" - android:textStyle="normal|bold" - android:typeface="normal" - android:layout_marginTop="15dp" - android:layout_below="@id/tv_schedule_location_content" - android:layout_alignStart="@+id/tv_schedule_citizen" /> - <TextView - android:id="@+id/tv_schedule_type_content" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="14sp" - android:typeface="normal" - android:layout_marginStart="3dp" - android:layout_alignBaseline="@+id/tv_schedule_type" - android:layout_alignBottom="@+id/tv_schedule_type" - android:layout_toEndOf="@+id/tv_schedule_type"/> <TextView - android:id="@+id/tv_schedule_date" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/schedule_confirmation_date" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="16sp" - android:textStyle="normal|bold" - android:typeface="normal" android:layout_marginTop="15dp" - android:layout_below="@id/tv_schedule_type_content" - android:layout_alignStart="@+id/tv_schedule_citizen"/> + android:layout_marginStart="14dp" + android:textColor="@color/colorBlack" + android:textStyle="normal|bold" + android:text="@string/notification_time"/> - <TextView - android:id="@+id/tv_schedule_date_content" - android:layout_width="wrap_content" + + <Spinner + android:id="@+id/spnr_schedule_time" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="14sp" - android:typeface="normal" + android:layout_marginTop="2dp" android:layout_marginStart="3dp" - android:layout_alignBaseline="@+id/tv_schedule_date" - android:layout_alignBottom="@+id/tv_schedule_date" - android:layout_toEndOf="@+id/tv_schedule_date"/> + android:layout_marginEnd="3dp"/> + <TextView - android:id="@+id/tv_schedule_street" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/schedule_confirmation_street" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="16sp" - android:textStyle="normal|bold" - android:typeface="normal" android:layout_marginTop="15dp" - android:layout_below="@id/tv_schedule_date_content" - android:layout_alignStart="@+id/tv_schedule_citizen"/> + android:layout_marginStart="14dp" + android:textColor="@color/colorBlack" + android:textStyle="normal|bold" + android:text="@string/notification_email_question"/> - <TextView - android:id="@+id/tv_schedule_street_content" + <RadioGroup android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textSize="14sp" - android:typeface="normal" - android:layout_marginStart="3dp" - android:layout_alignBaseline="@+id/tv_schedule_street" - android:layout_alignBottom="@+id/tv_schedule_street" - android:layout_toEndOf="@+id/tv_schedule_street"/> + android:layout_marginStart="14dp" + android:layout_height="wrap_content"> - </RelativeLayout> + <RadioButton + android:id="@+id/rb_notify_email_yes" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/yes"/> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:layout_marginTop="50dp"> + <RadioButton + android:id="@+id/rb_notify_email_no" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/no"/> - <Button - android:id="@+id/btn_schedule_back" - android:layout_width="wrap_content" + </RadioGroup> + + + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/gray_container_shape" - android:text="@string/back" - /> + android:layout_marginTop="10dp"> - <Button - android:id="@+id/btn_schedule_confirm" - android:layout_width="wrap_content" + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center"> + + <TextView + android:id="@+id/tv_schedule_email" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="14dp" + android:layout_marginEnd="14dp" + android:text="@string/notification_email_dest" + android:textColor="@color/colorBlack" + android:textStyle="normal|bold" + android:textSize="16sp" /> + + <TextView + android:id="@+id/tv_schedule_email_warning" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:layout_marginStart="5dp" + android:text="@string/invalid_email" + android:textColor="@color/colorRed" + android:textSize="12sp" + android:visibility="invisible" /> + + </FrameLayout> + + <EditText + android:id="@+id/et_schedule_email" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="14dp" + android:layout_marginEnd="14dp" + android:layout_marginTop="5dp" + android:maxLines="1" + android:textColor="@color/colorBlack" + android:textStyle="normal|bold" + android:inputType="textEmailAddress"/> + + + </LinearLayout> + + + + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/green_button_shape" - android:text="@string/schedule" - android:layout_marginStart="20dp" - /> + android:gravity="center" + android:layout_marginTop="30dp" + android:layout_marginBottom="30dp"> - </LinearLayout> + <Button + android:id="@+id/btn_schedule_back" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/gray_container_shape" + android:text="@string/back" + /> + <Button + android:id="@+id/btn_schedule_confirm" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/green_button_shape" + android:text="@string/schedule" + android:layout_marginStart="20dp" + /> + + </LinearLayout> + + </LinearLayout> + </ScrollView> - </LinearLayout> <ProgressBar android:id="@+id/pb_schedule_confirmation" diff --git a/app/src/main/res/values/integer.xml b/app/src/main/res/values/integer.xml index d0c1abf..b8d2b0f 100644 --- a/app/src/main/res/values/integer.xml +++ b/app/src/main/res/values/integer.xml @@ -3,4 +3,17 @@ <integer name="max_length_name">150</integer> + <string-array name="notification_time_int"> + <item>0</item> + <item>15</item> + <item>30</item> + <item>45</item> + <item>60</item> + <item>120</item> + <item>180</item> + <item>240</item> + <item>300</item> + <item>1440</item> + </string-array> + </resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 383c0dc..5e1f645 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -203,5 +203,23 @@ <string name="menu_sign_out">Sair</string> <string name="menu_edit">Editar</string> <string name="menu_sync">Sincronizar</string> + <string name="notification_email_question">Notificar também por e-mail?</string> + <string name="notification_time">Notificar sobre o agendamento:</string> + <string name="notification_email_dest">Digite o e-mail:</string> + + <string-array name="notification_time"> + <item>Não notificar</item> + <item>15 minutos antes</item> + <item>30 minutos antes</item> + <item>45 minutos antes</item> + <item>1 hora antes</item> + <item>2 horas antes</item> + <item>3 horas antes</item> + <item>4 horas antes</item> + <item>5 horas antes</item> + <item>1 dia antes</item> + </string-array> + + <string name="not_valid_email">Digite um e-mail válido.</string> </resources> -- GitLab From 7ca79e1148390a908ef0c9a7220c10d530815e28 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Tue, 19 Dec 2017 11:16:26 -0200 Subject: [PATCH 2/9] AGILE#271: Re-schedule notifications on device boot Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- app/src/main/AndroidManifest.xml | 18 ++- .../agendador/CitizenListActivity.java | 4 +- .../agendador/agendador/HomeActivity.java | 16 +++ .../ScheduleConfirmationActivity.java | 131 ++++++++++++------ .../agendador/SchedulesActivity.java | 25 +++- .../agendador/SchedulesHistoryActivity.java | 6 +- .../agendador/SchedulingActivity.java | 1 + .../agendador/agendador/helpers/Utils.java | 24 +++- .../SchedulesExpandableListAdapter.java | 2 +- .../listeners}/SpinnerActivity.java | 2 +- .../helpers/listeners/SpinnerListener.java | 2 - .../agendador/models/CheckSchedules.java | 65 +++++++-- .../agendador/models/Notification.java | 10 ++ .../agendador/models/NotificationReturn.java | 45 ++++++ .../agendador/models/ScheduleNote.java | 2 +- .../agendador/network/ApiEndpoints.java | 3 +- .../agendador/agendador/network/ApiUtils.java | 4 +- .../agendador/presenters/LoginPresenter.java | 17 ++- .../ScheduleConfirmationPresenter.java | 42 +++--- .../presenters/SchedulesHistoryPresenter.java | 2 + .../presenters/SchedulesPresenter.java | 1 + .../agendador/services/BootReceiver.java | 72 ++++++++++ .../LocalNotificationManager.java | 127 +++++++++++++++++ .../NotificationCreateService.java | 16 ++- .../notification/NotificationReceiver.java | 67 +++++++++ .../layout/content_schedule_confirmation.xml | 25 +++- app/src/main/res/values/integer.xml | 22 +-- app/src/main/res/values/strings.xml | 7 +- 28 files changed, 628 insertions(+), 130 deletions(-) rename app/src/main/java/br/ufpr/c3sl/agendador/agendador/{views => helpers/listeners}/SpinnerActivity.java (67%) create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java rename app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/{ => notification}/NotificationCreateService.java (82%) create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2497fce..ef2648c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,6 +16,8 @@ android:maxSdkVersion="18" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> + <application android:allowBackup="false" android:icon="@mipmap/ic_launcher" @@ -48,7 +50,7 @@ </service> <service - android:name=".services.NotificationCreateService" + android:name=".services.notification.NotificationCreateService" android:exported="false" android:permission="android.permission.BIND_JOB_SERVICE"> <intent-filter> @@ -56,6 +58,16 @@ </intent-filter> </service> + + <receiver android:name=".services.BootReceiver"> + <intent-filter> + <action android:name="android.intent.action.BOOT_COMPLETED"/> + </intent-filter> + </receiver> + + <receiver android:name=".services.notification.NotificationReceiver"> + </receiver> + <activity android:name=".TermActivity" /> <activity android:name=".SchedulingActivity"/> <activity android:name=".CitizenListActivity" /> @@ -67,6 +79,10 @@ <activity android:name=".RetrievalSuccessActivity" /> <activity android:name=".SchedulesHistoryActivity" /> <activity android:name=".ScheduleInfoActivity" /> + + + + </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/CitizenListActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/CitizenListActivity.java index 5c337c5..055b349 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/CitizenListActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/CitizenListActivity.java @@ -167,7 +167,9 @@ public class CitizenListActivity extends AppCompatActivity implements CitizenVie @Override public void onDismiss(DialogInterface dialog) { super.onDismiss(dialog); - getActivity().onBackPressed(); + Activity activity = getActivity(); + if(activity != null) + activity.onBackPressed(); } } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/HomeActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/HomeActivity.java index d791835..2c42be7 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/HomeActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/HomeActivity.java @@ -21,6 +21,7 @@ import android.support.v7.widget.ActionMenuView; import android.support.v7.widget.Toolbar; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; +import android.util.Log; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; @@ -29,11 +30,18 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.List; + import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; import br.ufpr.c3sl.agendador.agendador.helpers.UserImgHelper; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; +import br.ufpr.c3sl.agendador.agendador.models.Notification; import br.ufpr.c3sl.agendador.agendador.presenters.HomePresenter; import br.ufpr.c3sl.agendador.agendador.presenters.PresenterManager; +import br.ufpr.c3sl.agendador.agendador.services.notification.LocalNotificationManager; import br.ufpr.c3sl.agendador.agendador.views.HomeView; /** @@ -171,6 +179,14 @@ public class HomeActivity extends AppCompatActivity implements HomeView, }); changeTextColor(); showSnackBar(getIntent()); + + + /* + Notification notification = new Notification(1, "2017-12-18T10:10:00.000-0200", false, "Alo Alo", "a@a.c", false); + Log.d("Agendador", "Criando notificação"); + LocalNotificationManager.createLocalNotification(this, notification, osb, new Gson()); + */ + } @TargetApi(23) diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java index d08497d..885780f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java @@ -16,6 +16,7 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.view.menu.MenuBuilder; import android.support.v7.widget.ActionMenuView; import android.support.v7.widget.Toolbar; +import android.util.Log; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; @@ -32,7 +33,6 @@ import android.widget.Toast; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.Date; import java.util.Locale; import br.ufpr.c3sl.agendador.agendador.helpers.ConnectionErrorDialog; @@ -40,7 +40,8 @@ import br.ufpr.c3sl.agendador.agendador.helpers.DateValidator; import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; import br.ufpr.c3sl.agendador.agendador.helpers.UserImgHelper; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; -import br.ufpr.c3sl.agendador.agendador.models.CheckSchedules; +import br.ufpr.c3sl.agendador.agendador.helpers.listeners.SpinnerActivity; +import br.ufpr.c3sl.agendador.agendador.helpers.listeners.SpinnerListener; import br.ufpr.c3sl.agendador.agendador.models.CitizenCompact; import br.ufpr.c3sl.agendador.agendador.models.Notification; import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; @@ -53,7 +54,9 @@ import br.ufpr.c3sl.agendador.agendador.views.ScheduleConfirmationView; */ -public class ScheduleConfirmationActivity extends AppCompatActivity implements ScheduleConfirmationView, NavigationView.OnNavigationItemSelectedListener{ +public class ScheduleConfirmationActivity extends AppCompatActivity implements ScheduleConfirmationView, NavigationView.OnNavigationItemSelectedListener, SpinnerActivity{ + + private int[] reminderTimeArray; private ScheduleConfirmationPresenter scheduleConfirmationPresenter; @@ -69,13 +72,11 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S private EditText et_email; - private TextView tv_email_warning; + private TextView tv_email_warning, tv_email; private Button bt_schedule, bt_back; - private String[] notificationTime; - - private static String SPINNER_POS = "spinner_position"; + private static final String SPINNER_POS = "spinner_position"; private Spinner sp_notification; @@ -93,19 +94,28 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S Bundle bundle = getIntent().getBundleExtra(Utils.SCHEDULE_BUNDLE); final CitizenCompact citizen = bundle.getParcelable(Utils.CITIZEN); final ScheduleConfirmation scheduleConfirmation = bundle.getParcelable(Utils.SCHEDULE_CONFIRMATION); - String sectorName = scheduleConfirmation.getSectorName(); - String locationName = scheduleConfirmation.getLocationName(); - String typeName = scheduleConfirmation.getServiceTypeName(); - String address = scheduleConfirmation.getAddressStreet() + ", " + scheduleConfirmation.getAddressNumber(); + String sectorName = ""; + String locationName = ""; + String typeName = ""; + String address = ""; + if (scheduleConfirmation != null) { + sectorName = scheduleConfirmation.getSectorName(); + locationName = scheduleConfirmation.getLocationName(); + typeName = scheduleConfirmation.getServiceTypeName(); + address = scheduleConfirmation.getAddressStreet() + ", " + scheduleConfirmation.getAddressNumber(); + }else{ + Log.e("Agendador", "Bundle chegou vazio ou Schedule confirmation null " + + "ou citizenCompact null na classe ScheduleConfirmationActivity"); + } Toolbar toolbar = (Toolbar) findViewById(R.id.agendador_toolbar); toolbar.setTitle(null); setSupportActionBar(toolbar); ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(this, "Agendador", Context.MODE_PRIVATE); - String citizenName = osb.getString("name", null); - String citizenCity = osb.getString("city.name", null); - id = osb.getLong("id", 0); + String citizenName = osb.getString(Utils.NAME, null); + String citizenCity = osb.getString(Utils.CITY_NAME, null); + id = osb.getLong(Utils.ID, 0); ActionMenuView actionMenuView = (ActionMenuView) toolbar.findViewById(R.id.agendador_toolbar_menu); menuBuilder = (MenuBuilder) actionMenuView.getMenu(); @@ -161,14 +171,12 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S navigationView.setNavigationItemSelectedListener(this); - notificationTime = getResources().getStringArray(R.array.notification_time); + String[] notificationTime = getResources().getStringArray(R.array.notification_time); sp_notification = (Spinner) findViewById(R.id.spnr_schedule_time); sp_notification.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, notificationTime)); - sp_notification.setSelection(1, true); - pb_scheduleConfirmation = (ProgressBar) findViewById(R.id.pb_schedule_confirmation); TextView tv_citizen = (TextView) findViewById(R.id.tv_schedule_citizen_content); @@ -179,6 +187,7 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S TextView tv_street = (TextView) findViewById(R.id.tv_schedule_street_content); et_email = (EditText) findViewById(R.id.et_schedule_email); tv_email_warning = (TextView) findViewById(R.id.tv_schedule_email_warning); + final EditText et_scheduleNote = (EditText) findViewById(R.id.et_schedule_note); tv_sector.setText(sectorName); tv_citizen.setText(citizen.getName()); @@ -205,22 +214,18 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S }else{ tv_email_warning.setVisibility(View.INVISIBLE); } - } if(schedule){ - - scheduleConfirmationPresenter.onScheduleClicked(scheduleConfirmation, citizen); + scheduleConfirmationPresenter.onScheduleClicked(scheduleConfirmation, citizen, et_scheduleNote.getText().toString()); bt_schedule.setEnabled(false); bt_back.setEnabled(false); - } - } }); - final TextView tv_email = (TextView) findViewById(R.id.tv_schedule_email); + tv_email = (TextView) findViewById(R.id.tv_schedule_email); rb_yes = (RadioButton) findViewById(R.id.rb_notify_email_yes); @@ -231,23 +236,16 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S rb_yes.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - rb_no.setChecked(false); - et_email.setEnabled(true); - tv_email.setTextColor(Color.BLACK); - if(sp_notification.getSelectedItemPosition() == 0){ - sp_notification.setSelection(1, true); - } + //Radio Button already toggled from user click. + radioButtonNotificationSelected(R.id.rb_notify_email_yes, false); } }); rb_no.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - rb_yes.setChecked(false); - et_email.setEnabled(false); - et_email.setText(""); - tv_email.setTextColor(Color.GRAY); - tv_email_warning.setVisibility(View.INVISIBLE); + //Radio Button already toggled from user click. + radioButtonNotificationSelected(R.id.rb_notify_email_no, false); } }); @@ -261,11 +259,17 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S if(savedInstanceState == null){ scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(getBaseContext()); }else{ - sp_notification.setSelection( savedInstanceState.getInt(SPINNER_POS, 1), true); scheduleConfirmationPresenter = PresenterManager.getInstance().restorePresenter(savedInstanceState); if(scheduleConfirmationPresenter == null) scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(this); } + + + SpinnerListener notificationListener = new SpinnerListener(this); + sp_notification.setOnItemSelectedListener(notificationListener); + sp_notification.setOnTouchListener(notificationListener); + + reminderTimeArray = getResources().getIntArray(R.array.notification_time_milis); } @Override @@ -365,19 +369,25 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S @Override public void onSuccess(ScheduleConfirmation schedule){ - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ", Locale.getDefault()); + SimpleDateFormat sdfServer = new SimpleDateFormat(Utils.SERVER_FORMAT, Locale.getDefault()); + SimpleDateFormat sdfDate = new SimpleDateFormat(Utils.DATE_FORMAT, Locale.getDefault()); + SimpleDateFormat sdfHour = new SimpleDateFormat(Utils.HOUR_FORMAT, Locale.getDefault()); + + /* * Position zero is "don't notify" */ - int reminderTimeArray[] = getResources().getIntArray(R.array.notification_time_int); - if(sp_notification.getSelectedItemPosition() != 0 ){ + if(sp_notification.getSelectedItemPosition() != reminderTimeArray.length - 1){ Notification notification = new Notification(); notification.scheduleId = schedule.getId(); notification.emailSent = false; - notification.description = "a"; - //reminderTime*1000 to transform milliseconds to minutes. - notification.reminderTime = sdf.format(schedule.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()]*1000)); + + notification.description = getResources().getString(R.string.notification_content, schedule.getServiceTypeName(), + schedule.getLocationName(), schedule.getAddressStreet(), schedule.getAddressNumber(), + sdfDate.format(schedule.getStartTime()), sdfHour.format(schedule.getStartTime())); + + notification.reminderTime = sdfServer.format(schedule.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()])); if(rb_yes.isChecked()){ notification.emailAddres = et_email.getText().toString(); @@ -390,6 +400,28 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S } + + private void radioButtonNotificationSelected(int id, boolean toggle){ + switch (id){ + case R.id.rb_notify_email_no: + if(toggle) { + rb_no.toggle(); + } + et_email.setEnabled(false); + et_email.setText(""); + tv_email.setTextColor(Color.GRAY); + tv_email_warning.setVisibility(View.INVISIBLE); + break; + case R.id.rb_notify_email_yes: + if(toggle){ + rb_yes.toggle(); + } + et_email.setEnabled(true); + tv_email.setTextColor(Color.BLACK); + break; + } + } + @Override public void returnHome(){ Intent intent = new Intent(ScheduleConfirmationActivity.this, HomeActivity.class); @@ -398,6 +430,7 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S bundle.putInt(HomeActivity.SHOW_SCHEDULE_SNACKBAR, 1); intent.putExtra(HomeActivity.SHOW_SCHEDULE_SNACKBAR,bundle); startActivity(intent); + finish(); } @Override @@ -426,6 +459,22 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S } } + @Override + public void updateSpinners(int id) { + switch (id){ + case R.id.spnr_schedule_time: + if(sp_notification.getSelectedItemPosition() == reminderTimeArray.length - 1){ + radioButtonNotificationSelected(R.id.rb_notify_email_no, true); + rb_no.setEnabled(false); + rb_yes.setEnabled(false); + }else{ + rb_no.setEnabled(true); + rb_yes.setEnabled(true); + } + break; + } + } + public static class ConfirmationDialog extends DialogFragment { @Override diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java index c07d3ce..904dde0 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java @@ -117,7 +117,17 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi final DrawerLayout drawer; ActionMenuView actionMenuView = (ActionMenuView) toolbar.findViewById(R.id.agendador_toolbar_menu); menuBuilder = (MenuBuilder) actionMenuView.getMenu(); + menuBuilder.setCallback(new MenuBuilder.Callback() { + @Override + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + return onOptionsItemSelected(item); + } + @Override + public void onMenuModeChange(MenuBuilder menu) { + + } + }); ImageView drawerHamburger = (ImageView) toolbar.findViewById(R.id.img_toolbar_hamburger); @@ -153,6 +163,7 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi }); + navigationView.setCheckedItem(R.id.nav_check_schedules); navigationView.setNavigationItemSelectedListener(this); @@ -239,9 +250,9 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi maxDate = new Date(); String date; - if(schedules.getSchedulesList() != null) { + if(schedules.getSchedules().getSchedulesList() != null) { - for (CheckSchedules.Schedule schedule : schedules.getSchedulesList()) { + for (CheckSchedules.Schedule schedule : schedules.getSchedules().getSchedulesList()) { date = dateFormat.format(schedule.getStartTime()); if(schedule.getStartTime().after(maxDate)){ maxDate = schedule.getStartTime(); @@ -261,7 +272,7 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi for (CheckSchedules.DependentSchedules dependentSchedules : schedules.getDependentSchedulesList()) { - for (CheckSchedules.Schedule schedule : dependentSchedules.getSchedulesList()){ + for (CheckSchedules.Schedule schedule : dependentSchedules.getScheduleListModel().getSchedulesList()){ date = dateFormat.format(schedule.getStartTime()); if(schedule.getStartTime().after(maxDate)){ maxDate = schedule.getStartTime(); @@ -403,8 +414,8 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi long id = 0; //searching if this schedule belongs to the citizen or the dependents. - for(int i = 0; i < schedules.getSchedulesList().size() && id == 0; ++i){ - if(schedules.getSchedulesList().get(i).getId() == selectedSchedule.getId()) + for(int i = 0; i < schedules.getSchedules().getSchedulesList().size() && id == 0; ++i){ + if(schedules.getSchedules().getSchedulesList().get(i).getId() == selectedSchedule.getId()) { id = schedules.getId(); name = schedules.getName(); @@ -412,8 +423,8 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi } for (int i = 0; i < schedules.getDependentSchedulesList().size() && id == 0; ++i){ - for(int j = 0; j < schedules.getDependentSchedulesList().get(i).getSchedulesList().size() && id == 0; ++j){ - if(schedules.getDependentSchedulesList().get(i).getSchedulesList().get(j).getId() == selectedSchedule.getId()) + for(int j = 0; j < schedules.getDependentSchedulesList().get(i).getScheduleListModel().getSchedulesList().size() && id == 0; ++j){ + if(schedules.getDependentSchedulesList().get(i).getScheduleListModel().getSchedulesList().get(j).getId() == selectedSchedule.getId()) { id = schedules.getDependentSchedulesList().get(i).getId(); name = schedules.getDependentSchedulesList().get(i).getName(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java index 12e6ecb..79e0272 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java @@ -47,7 +47,7 @@ import br.ufpr.c3sl.agendador.agendador.models.ServiceType; import br.ufpr.c3sl.agendador.agendador.presenters.PresenterManager; import br.ufpr.c3sl.agendador.agendador.presenters.SchedulesHistoryPresenter; import br.ufpr.c3sl.agendador.agendador.views.SchedulesHistoryView; -import br.ufpr.c3sl.agendador.agendador.views.SpinnerActivity; +import br.ufpr.c3sl.agendador.agendador.helpers.listeners.SpinnerActivity; public class SchedulesHistoryActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, SchedulesHistoryView, SpinnerActivity { @@ -756,11 +756,11 @@ public class SchedulesHistoryActivity extends AppCompatActivity implements Navig expandableListTitle = new ArrayList<>(); expandableListTitle.add(new Pair<>(schedules.getName(), schedules.getId())); - expandableListDetail.put(schedules.getName(), schedules.getSchedulesList()); + expandableListDetail.put(schedules.getName(), schedules.getSchedules().getSchedulesList()); for (CheckSchedules.DependentSchedules dependentSchedules : schedules.getDependentSchedulesList()) { expandableListTitle.add(new Pair<>(dependentSchedules.getName(), dependentSchedules.getId())); - expandableListDetail.put(dependentSchedules.getName(), dependentSchedules.getSchedulesList()); + expandableListDetail.put(dependentSchedules.getName(), dependentSchedules.getScheduleListModel().getSchedulesList()); } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java index 2df2714..7b996ae 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulingActivity.java @@ -328,6 +328,7 @@ public class SchedulingActivity extends AppCompatActivity implements SchedulingV mcv.setSelectionMode(MaterialCalendarView.SELECTION_MODE_NONE); + // TODO: 12/12/17 check here dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); hourFormat = new SimpleDateFormat("HH:mm", Locale.getDefault()); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java index 5e3f815..058d842 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java @@ -34,6 +34,14 @@ import br.ufpr.c3sl.agendador.agendador.models.UserOutput; public abstract class Utils { + public static final String DATE_HOUR_FORMAT = "dd/MM/yyyy - HH:mm"; + + public static final String HOUR_FORMAT = "HH:mm"; + + public static final String DATE_FORMAT = "dd/MM/yyyy"; + + public static final String SERVER_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + public final static String SERVICE_UPDATE_IMAGE = "br.c3sl.ufpr.image_update"; public static final String SECTORS_LIST = "sectors_list"; @@ -50,10 +58,10 @@ public abstract class Utils { public static final String SCHEDULE_CONFIRMATION = "selected_schedule"; - public static final String CITIZEN = "citizen_object"; + public static final String SIZE_LARGE = "large"; + public static final String CITIZEN = "citizen_object"; public static final String CITIZEN_BUNDLE = "br.ufpr.c3sl.agendador.agendador.citizen_bundle"; - public static final String JOB_FILE_NAME = "fileName_tag"; public static final String ADDRESS_NEIGHBORHOOD = "address.neighborhood"; public static final String ADDRESS_NUMBER = "address_number"; @@ -99,17 +107,25 @@ public abstract class Utils { public static final String CPF_MASK = "###.###.###-##"; public static final String BIRTH_DAY_MASK = "##/##/####"; public static final String SCHEDULE = "schedule"; - public static final String DATE_FORMAT = "MM/dd/yyyy HH:mm"; public static final String CALLER_ACTIVITY = "from_activity"; + + public static final int HISTORY_ACTIVITY = 1; public static final int SCHEDULES_ACTIVITY = 0; + + public static final String REQUEST_FILTER_SECTOR = "q[sector_id]"; public static final String REQUEST_FILTER_TYPE = "q[service_type_id]"; public static final String REQUEST_FILTER_PLACE = "q[service_place_id]"; public static final String REQUEST_FILTER_SITUATION = "q[situation_id]"; - public static final String SIZE_LARGE = "large"; + + public static final String NOTIFICATION = "notification"; public static final String NOTIFICATION_SERVICE = "br.c3sl.ufpr.notification_service"; + public static final String NOTIFICATION_LIST = "notification_list"; + + + public static final String ACTION_SHOW_NOTIFICATION = "br.ufpr.c3sl.agendador.SHOW_NOTIFICATION"; public static int getPixelValue(int dp, Context context) { Resources resources = context.getResources(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/adapters/SchedulesExpandableListAdapter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/adapters/SchedulesExpandableListAdapter.java index 91db747..624d9a1 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/adapters/SchedulesExpandableListAdapter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/adapters/SchedulesExpandableListAdapter.java @@ -37,7 +37,7 @@ public class SchedulesExpandableListAdapter extends BaseExpandableListAdapter { this.context = context; this.expandableListTitle = expandableListTitle; this.expandableListDetail = expandableListDetail; - dateFormat = new SimpleDateFormat(Utils.DATE_FORMAT, Locale.getDefault()); + dateFormat = new SimpleDateFormat(Utils.DATE_HOUR_FORMAT, Locale.getDefault()); } @Override diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/SpinnerActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerActivity.java similarity index 67% rename from app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/SpinnerActivity.java rename to app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerActivity.java index f8c31cc..449c737 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/SpinnerActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerActivity.java @@ -1,4 +1,4 @@ -package br.ufpr.c3sl.agendador.agendador.views; +package br.ufpr.c3sl.agendador.agendador.helpers.listeners; /** * Created by Lucas Braz Cunha on 22/11/17. diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerListener.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerListener.java index f3d9d4e..ea90e52 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerListener.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/listeners/SpinnerListener.java @@ -4,8 +4,6 @@ import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; -import br.ufpr.c3sl.agendador.agendador.views.SpinnerActivity; - /** * Created by Lucas Braz Cunha on 22/11/17. */ diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java index 5549420..2dc9b0a 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java @@ -21,7 +21,7 @@ public class CheckSchedules { String name; @SerializedName("schedules") - private List<Schedule> schedulesList; + ScheduleListModel schedules; @SerializedName("dependants") private List<DependentSchedules> dependentSchedulesList; @@ -34,13 +34,17 @@ public class CheckSchedules { return name; } - public CheckSchedules(long id, String name, List<Schedule> schedulesList, List<DependentSchedules> dependentSchedulesList) { + public CheckSchedules(long id, String name, ScheduleListModel schedules, List<DependentSchedules> dependentSchedulesList) { this.id = id; this.name = name; - this.schedulesList = schedulesList; + this.schedules = schedules; this.dependentSchedulesList = dependentSchedulesList; } + public ScheduleListModel getSchedules() { + return schedules; + } + public static class Schedule implements Parcelable{ @SerializedName("id") @@ -154,6 +158,11 @@ public class CheckSchedules { } + + public List<DependentSchedules> getDependentSchedulesList() { + return dependentSchedulesList; + } + public static class DependentSchedules{ @SerializedName("id") @@ -163,11 +172,7 @@ public class CheckSchedules { String name; @SerializedName("schedules") - List<Schedule> schedulesList; - - public List<Schedule> getSchedulesList() { - return schedulesList; - } + ScheduleListModel scheduleListModel; public long getId() { return id; @@ -176,20 +181,50 @@ public class CheckSchedules { public String getName() { return name; } - - public DependentSchedules(long id, String name, List<Schedule> scheduleList) { + public DependentSchedules(long id, String name) { this.id = id; this.name = name; - this.schedulesList = scheduleList; + } + + public ScheduleListModel getScheduleListModel() { + return scheduleListModel; } } - public List<Schedule> getSchedulesList() { - return schedulesList; + public static class ScheduleListModel { + + @SerializedName("num_entries") + int listSize; + + @SerializedName("entries") + List<Schedule> schedulesList; + + @SerializedName("sectors") + List<SectorScheduleModel> sectorScheduleModels; + + + public List<Schedule> getSchedulesList() { + return schedulesList; + } + + public int getListSize() { + return listSize; + } } - public List<DependentSchedules> getDependentSchedulesList() { - return dependentSchedulesList; + public static class SectorScheduleModel { + @SerializedName("id") + int sectorId; + + @SerializedName("name") + String name; + + @SerializedName("schedules_by_sector") + int chedulesbySector; + + @SerializedName("schedules") + int schedules; } + } \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java index 1811b3c..c43de20 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java @@ -9,6 +9,7 @@ import com.google.gson.annotations.SerializedName; * Created by Lucas Braz Cunha on 24/11/17. */ + public class Notification implements Parcelable{ @SerializedName("schedule_id") @@ -33,6 +34,15 @@ public class Notification implements Parcelable{ public Notification() { } + public Notification(long scheduleId, String reminderTime, boolean hasRead, String description, String emailAddress, boolean emailSent) { + this.scheduleId = scheduleId; + this.reminderTime = reminderTime; + this.hasRead = hasRead; + this.description = description; + this.emailAddres = emailAddress; + this.emailSent = emailSent; + } + /**reads back fields IN THE ORDER they were written */ private Notification(Parcel pc){ scheduleId = pc.readLong(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java new file mode 100644 index 0000000..022bcf3 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java @@ -0,0 +1,45 @@ +package br.ufpr.c3sl.agendador.agendador.models; + +import com.google.gson.annotations.SerializedName; + +/** + * Created by Lucas Braz Cunha on 18/12/17. + */ + +public class NotificationReturn{ + + @SerializedName("id") + public long notificationId; + + @SerializedName("account_id") + public long accountId; + + @SerializedName("schedule_id") + public Long scheduleId; + + @SerializedName("resource_schedule_id") + public Long resourceScheduleId; + + @SerializedName("reminder_time") + public String reminderTime; + + @SerializedName("read") + public int hasRead; + + @SerializedName("content") + public String description; + + @SerializedName("reminder_email") + public String emailAddres; + + @SerializedName("reminder_email_sent") + public int emailSent; + + @SerializedName("created_at") + public String createdAt; + + @SerializedName("updated_at") + public String updatedAt; + + +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java index 3f394cc..8397ca4 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java @@ -8,7 +8,7 @@ import com.google.gson.annotations.SerializedName; public class ScheduleNote { - private Schedule schedule; + public Schedule schedule; public ScheduleNote(String note) { this.schedule = new Schedule(note); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java index 1d1aab1..0683147 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java @@ -15,6 +15,7 @@ import br.ufpr.c3sl.agendador.agendador.models.DependentCreation; 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.ScheduleConfirmation; import br.ufpr.c3sl.agendador.agendador.models.ScheduleNote; import br.ufpr.c3sl.agendador.agendador.models.SectorInput; @@ -92,7 +93,7 @@ public interface ApiEndpoints { Call<FormFilters> requestCitizenSectors(); @POST("notifications?permission=2") - Call<ScheduleConfirmation> requestCreateNotification(@Body Notification notification); + Call<NotificationReturn> requestCreateNotification(@Body Notification notification); } \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java index 14ec54a..c4d09fd 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java @@ -14,8 +14,8 @@ import retrofit2.converter.gson.GsonConverterFactory; */ public abstract class ApiUtils { - public static final String BASE_URL = "http://10.0.2.2:3000/v1/"; -// public static final String BASE_URL = "http://newcastle.c3sl.ufpr.br/develop/v1/"; +// public static final String BASE_URL = "http://10.0.2.2:3000/v1/"; + public static final String BASE_URL = "http://newcastle.c3sl.ufpr.br/develop/v1/"; public static ApiEndpoints request(final Map<String, String> header) { OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java index fa5040c..6416763 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; +import android.widget.Toast; import com.firebase.jobdispatcher.Constraint; import com.firebase.jobdispatcher.FirebaseJobDispatcher; @@ -107,6 +108,8 @@ public class LoginPresenter extends BasePresenter<LoginView> { break; default: Log.d("Login Request", "Voltou " + status + "!!!"); + loginPresenter.view().setProgressBar(false); + Toast.makeText(context, "Ocorreu um erro ao logar.", Toast.LENGTH_SHORT).show(); break; } } @@ -197,19 +200,21 @@ public class LoginPresenter extends BasePresenter<LoginView> { final String uid = osb.getString(Utils.UID, null); String compare, children[]; - Locale locale = new Locale("pt", "BR"); - DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", locale); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + + DateFormat sdf = new SimpleDateFormat(Utils.SERVER_FORMAT, Locale.getDefault()); sdf.setLenient(false); Date fileDate = null; //in case of parsing exception, it will request image from server and app won't crash. Date serverDate = Calendar.getInstance().getTime(); + Log.d("Agendador", "Data sem parsear:" + osb.getString(Utils.AVATAR_UPDATED_AT, "")); try { serverDate = sdf.parse(osb.getString(Utils.AVATAR_UPDATED_AT, "")); - } catch (ParseException e) { - e.printStackTrace(); + Log.d("Agendador", "Data parseada:" + sdf.format(serverDate)); + } catch (ParseException ignored) { + //in case of parse exception request from server + ignored.printStackTrace(); } File dir = new File(context.getExternalFilesDir(null) + File.separator + Utils.DIR_PICTRS + File.separator); @@ -238,8 +243,6 @@ public class LoginPresenter extends BasePresenter<LoginView> { loginPresenter.view().setProgressBar(false); loginPresenter.view().afterSuccessfulLogin(); } - - } } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java index 9ccd9c2..b9f086e 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java @@ -1,7 +1,6 @@ package br.ufpr.c3sl.agendador.agendador.presenters; import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.util.Log; @@ -17,19 +16,18 @@ import com.google.gson.Gson; import java.util.HashMap; import java.util.Map; -import br.ufpr.c3sl.agendador.agendador.LoginActivity; import br.ufpr.c3sl.agendador.agendador.ScheduleConfirmationActivity; import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; import br.ufpr.c3sl.agendador.agendador.models.CitizenCompact; import br.ufpr.c3sl.agendador.agendador.models.Notification; +import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn; import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; import br.ufpr.c3sl.agendador.agendador.models.ScheduleNote; -import br.ufpr.c3sl.agendador.agendador.models.UserOutput; import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints; import br.ufpr.c3sl.agendador.agendador.network.ApiUtils; -import br.ufpr.c3sl.agendador.agendador.services.ImageUpdateService; -import br.ufpr.c3sl.agendador.agendador.services.NotificationCreateService; +import br.ufpr.c3sl.agendador.agendador.services.notification.LocalNotificationManager; +import br.ufpr.c3sl.agendador.agendador.services.notification.NotificationCreateService; import okhttp3.Headers; import retrofit2.Call; import retrofit2.Callback; @@ -56,7 +54,7 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm } - public void onScheduleClicked(final ScheduleConfirmation scheduleConfirmation, CitizenCompact citizen){ + public void onScheduleClicked(final ScheduleConfirmation scheduleConfirmation, CitizenCompact citizen, String note){ Map<String, String> header = new HashMap<>(); header.put("Content-Type", "application/json"); header.put(Utils.ACCESS_TOKEN, osb.getString(Utils.ACCESS_TOKEN, null)); @@ -65,9 +63,9 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm final ApiEndpoints service = ApiUtils.request(header); - ScheduleNote note = new ScheduleNote(""); + ScheduleNote scheduleNote = new ScheduleNote(note); - Call<ScheduleConfirmation> listCall = service.requestPerformScheduling(scheduleConfirmation.getId(), citizen.getId(), note); + Call<ScheduleConfirmation> listCall = service.requestPerformScheduling(scheduleConfirmation.getId(), citizen.getId(), scheduleNote); scheduleConfirmationPresenter.view().setProgressBar(true); listCall.enqueue(new Callback<ScheduleConfirmation>() { @@ -76,13 +74,13 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm public void onResponse(Call<ScheduleConfirmation> call, Response<ScheduleConfirmation> response) { Headers headers = response.headers(); int status = response.code(); - ScheduleConfirmation confirmationResponse = response.body(); + updateHeaders(headers); switch (status) { case 200: Log.d("Server response", this.getClass().getName() + ": 200 - Sucesso!"); scheduleConfirmationPresenter.view().setProgressBar(false); - scheduleConfirmationPresenter.view().onSuccess(confirmationResponse); + scheduleConfirmationPresenter.view().onSuccess(scheduleConfirmation); break; default: @@ -111,30 +109,29 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm header.put(Utils.CLIENT, osb.getString(Utils.CLIENT, null)); header.put(Utils.UID, osb.getString(Utils.UID, null)); - final ApiEndpoints service = ApiUtils.request(header); + final ApiEndpoints service = ApiUtils.request(header); - // TODO: 24/11/17 arrumar retorno - Call<ScheduleConfirmation> listCall = service.requestCreateNotification(notification); + final Call<NotificationReturn> listCall = service.requestCreateNotification(notification); scheduleConfirmationPresenter.view().setProgressBar(true); - listCall.enqueue(new Callback<ScheduleConfirmation>() { + listCall.enqueue(new Callback<NotificationReturn>() { @Override - public void onResponse(Call<ScheduleConfirmation> call, Response<ScheduleConfirmation> response) { + public void onResponse(Call<NotificationReturn> call, Response<NotificationReturn> response) { Headers headers = response.headers(); int status = response.code(); - //ScheduleConfirmation confirmationResponse = response.body(); + Log.d("Agendador", "Header do create notification:" + headers.get(Utils.ACCESS_TOKEN)); updateHeaders(headers); switch (status) { - case 200: + 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()); break; default: - Log.e("Server response", this.getClass().getName() + ": ERRO:" + status + ". Scheduling job"); + Log.e("Server response", this.getClass().getName() + ": ERRO:" + status + " na criação de uma notificação."); scheduleNotificationJob(notification); scheduleConfirmationPresenter.view().setProgressBar(false); scheduleConfirmationPresenter.view().returnHome(); @@ -142,11 +139,10 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm } } @Override - public void onFailure(Call<ScheduleConfirmation> call, Throwable t) { + public void onFailure(Call<NotificationReturn> call, Throwable t) { Log.e("Server response", this.getClass().getName() + ": Request Failed, Scheduling job."); - + t.printStackTrace(); scheduleNotificationJob(notification); - scheduleConfirmationPresenter.view().setProgressBar(false); scheduleConfirmationPresenter.view().returnHome(); } @@ -168,7 +164,7 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm .setService(NotificationCreateService.class) .setTag(Utils.NOTIFICATION_SERVICE) //time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600 - .setTrigger(Trigger.executionWindow(0, 3600)) + .setTrigger(Trigger.executionWindow(10, 3600)) //will be retried if it fails. .setRecurring(true) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesHistoryPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesHistoryPresenter.java index 42a77ce..0055f12 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesHistoryPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesHistoryPresenter.java @@ -77,6 +77,7 @@ public class SchedulesHistoryPresenter extends BasePresenter<SchedulesHistoryAct presenter.view().setNoConnection(true); presenter.view().enableSpinners(false); presenter.view().enableButtons(false); + t.printStackTrace(); } }); @@ -124,6 +125,7 @@ public class SchedulesHistoryPresenter extends BasePresenter<SchedulesHistoryAct presenter.view().setNoConnection(true); presenter.view().setProgressBar(false); presenter.view().enableSpinners(true); + t.printStackTrace(); } }); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java index c8197a6..bfdd7a0 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java @@ -80,6 +80,7 @@ public class SchedulesPresenter extends BasePresenter<SchedulesActivity> { presenter.view().setNoConnection(true); presenter.view().setProgressBar(false); presenter.view().blockCalendar(false); + t.printStackTrace(); } }); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java new file mode 100644 index 0000000..1786d10 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java @@ -0,0 +1,72 @@ +package br.ufpr.c3sl.agendador.agendador.services; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +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.services.notification.LocalNotificationManager; +import br.ufpr.c3sl.agendador.agendador.services.notification.NotificationReceiver; + +/** + * Created by Lucas Braz Cunha on 27/11/17. + * + * Receiver responsible for re-scheduling notifications on reboot, if it's needed. + */ + + +public class BootReceiver extends BroadcastReceiver { + + + @Override + public void onReceive(Context context, Intent intent) { + PendingResult result; + if (intent.getAction() != null && context != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { + // Set the alarm here. + result = goAsync(); + Date date; + Calendar calendar; + SimpleDateFormat sdfServer = new SimpleDateFormat(Utils.SERVER_FORMAT, Locale.getDefault()); + ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE); + + //Retrieve the values + Gson gson = new Gson(); + String jsonText = osb.getString(Utils.NOTIFICATION_LIST, null); + List<Notification> notifications = gson.fromJson(jsonText, new TypeToken<List<Notification>>(){}.getType()); + + + if (notifications != null) { + Log.d("Agendador", "Tamanho da lista:" + notifications.size()); + for (Notification notification: notifications) { + calendar = Calendar.getInstance(); + try { + date = sdfServer.parse(notification.reminderTime); + calendar.setTime(date); + LocalNotificationManager.setReminder(context, NotificationReceiver.class, calendar, (int) notification.scheduleId); + } catch (ParseException e) { + e.printStackTrace(); + } + } + } + + + result.finish(); + } + } + + + +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java new file mode 100644 index 0000000..e463eba --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java @@ -0,0 +1,127 @@ +package br.ufpr.c3sl.agendador.agendador.services.notification; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +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 static android.content.Context.ALARM_SERVICE; + +/** + * Utility Class to manipulate the local list of notifications. + * + * Created by Lucas Braz Cunha on 15/12/17. + */ + + + +public abstract class LocalNotificationManager { + + + private 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..."); + 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, NotificationReceiver.class, calendar, (int) notification.scheduleId); + }catch (ParseException ignored){ + Log.e("Agendador", "Erro ao parsear data, para criar notificação local."); + ignored.printStackTrace(); + } + } + + + public static void setReminder(Context context, Class<?> cls, Calendar calendar, int scheduleId){ + + Intent intent = new Intent(context, cls); + intent.setAction(Utils.ACTION_SHOW_NOTIFICATION); + intent.putExtra(Utils.ID, scheduleId); + + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, + NOTIFICATION_REMINDER_REQUEST_CODE + scheduleId, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE); + if(am != null){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); + }else { + am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); + } + + Log.d("Agendador", "Alarme registrado para o agendamento " + scheduleId + " ."); + } + else{ + Log.d("Agendador", "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); + + Log.d("Agendador", "add notification:" + jsonList); + + 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, ""); + return gson.fromJson(jsonList, new TypeToken<List<Notification>>(){}.getType()); + } + + // 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; + } + } + + jsonList = gson.toJson(notifications); + + Log.d("Agendador", "remove notification:" + jsonList); + + osb.edit().putString(Utils.NOTIFICATION_LIST, jsonList).commit(); + + } + + +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/NotificationCreateService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java similarity index 82% rename from app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/NotificationCreateService.java rename to app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java index 8169038..273300a 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/NotificationCreateService.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java @@ -1,4 +1,4 @@ -package br.ufpr.c3sl.agendador.agendador.services; +package br.ufpr.c3sl.agendador.agendador.services.notification; import android.content.Context; import android.os.Bundle; @@ -14,7 +14,7 @@ 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.Notification; -import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; +import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn; import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints; import br.ufpr.c3sl.agendador.agendador.network.ApiUtils; import okhttp3.Headers; @@ -53,12 +53,13 @@ public class NotificationCreateService extends JobService { ApiEndpoints service = ApiUtils.request(header); - Call<ScheduleConfirmation> listCall = service.requestCreateNotification(notification); + Call<NotificationReturn> listCall = service.requestCreateNotification(notification); - listCall.enqueue(new Callback<ScheduleConfirmation>() { + final Notification finalNotification = notification; + listCall.enqueue(new Callback<NotificationReturn>() { @Override - public void onResponse(Call<ScheduleConfirmation> call, Response<ScheduleConfirmation> response) { + public void onResponse(Call<NotificationReturn> call, Response<NotificationReturn> response) { int status = response.code(); Headers headers = response.headers(); ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(getBaseContext(), "Agendador", Context.MODE_PRIVATE); @@ -74,7 +75,7 @@ public class NotificationCreateService extends JobService { switch (status) { case 200: - + LocalNotificationManager.createLocalNotification(getApplicationContext(), finalNotification, osb, new Gson()); jobFinished(job, false); break; default: @@ -86,8 +87,9 @@ public class NotificationCreateService extends JobService { } @Override - public void onFailure(Call<ScheduleConfirmation> call, Throwable t) { + public void onFailure(Call<NotificationReturn> call, Throwable t) { Log.v("AGNDDR-NotifiCreate", "Job falhou e será remarcado!!"); + t.printStackTrace(); jobFinished(job, true); } }); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java new file mode 100644 index 0000000..326f2fe --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java @@ -0,0 +1,67 @@ +package br.ufpr.c3sl.agendador.agendador.services.notification; + +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.support.v7.app.NotificationCompat; +import android.util.Log; +import android.widget.Toast; + +import com.google.gson.Gson; + +import java.util.List; + +import br.ufpr.c3sl.agendador.agendador.R; +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 static android.content.Context.NOTIFICATION_SERVICE; + +/** + * Created by Lucas Braz Cunha on 27/11/17. + */ + +public class NotificationReceiver extends BroadcastReceiver{ + + + @Override + 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); + ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE); + Notification content = null; + Gson gson = new Gson(); + List<Notification> notifications = LocalNotificationManager.getList(osb, gson); + for(Notification n : notifications){ + if(n.scheduleId == id){ + content = n; + break; + } + } + 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; + } + + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context); + + String alert = context.getResources().getString(R.string.notification_alert); + android.app.Notification appNotification = mBuilder.setAutoCancel(true).setContentText(content.description).setContentTitle(alert) + .setDefaults(android.app.Notification.DEFAULT_LIGHTS | android.app.Notification.DEFAULT_SOUND) + .setSmallIcon(R.drawable.img_mainact_logo).setTicker(alert) + .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.img_terms_logo)).build(); + + // Will display the notification in the notification bar + notificationManager.notify(id, appNotification); + + } + } +} diff --git a/app/src/main/res/layout/content_schedule_confirmation.xml b/app/src/main/res/layout/content_schedule_confirmation.xml index d5a2107..28553d0 100644 --- a/app/src/main/res/layout/content_schedule_confirmation.xml +++ b/app/src/main/res/layout/content_schedule_confirmation.xml @@ -28,6 +28,7 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusableInTouchMode="true" android:orientation="vertical"> <TextView @@ -213,6 +214,28 @@ </RelativeLayout> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="15dp" + android:layout_marginStart="14dp" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:textSize="14sp" + android:typeface="normal" + android:text="@string/notification_note_text"/> + + <EditText + android:id="@+id/et_schedule_note" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_marginTop="5dp" + android:layout_marginStart="14dp" + android:layout_marginEnd="14dp" + android:textStyle="normal" + android:inputType="textAutoCorrect" + android:maxLength="140"/> + + <TextView android:layout_width="wrap_content" @@ -306,7 +329,7 @@ android:layout_marginTop="5dp" android:maxLines="1" android:textColor="@color/colorBlack" - android:textStyle="normal|bold" + android:textStyle="normal" android:inputType="textEmailAddress"/> diff --git a/app/src/main/res/values/integer.xml b/app/src/main/res/values/integer.xml index b8d2b0f..ffee45f 100644 --- a/app/src/main/res/values/integer.xml +++ b/app/src/main/res/values/integer.xml @@ -3,17 +3,17 @@ <integer name="max_length_name">150</integer> - <string-array name="notification_time_int"> + <integer-array name="notification_time_milis"> + <item>900000</item> + <item>1800000</item> + <item>2700000</item> + <item>3600000</item> + <item>7200000</item> + <item>10800000</item> + <item>240000</item> + <item>14400000</item> + <item>86400000</item> <item>0</item> - <item>15</item> - <item>30</item> - <item>45</item> - <item>60</item> - <item>120</item> - <item>180</item> - <item>240</item> - <item>300</item> - <item>1440</item> - </string-array> + </integer-array> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5e1f645..bf0e056 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -208,7 +208,6 @@ <string name="notification_email_dest">Digite o e-mail:</string> <string-array name="notification_time"> - <item>Não notificar</item> <item>15 minutos antes</item> <item>30 minutos antes</item> <item>45 minutos antes</item> @@ -218,8 +217,14 @@ <item>4 horas antes</item> <item>5 horas antes</item> <item>1 dia antes</item> + <item>Não notificar</item> </string-array> <string name="not_valid_email">Digite um e-mail válido.</string> + <string name="notification_content">%s em %s (%s, %d) %s às %s</string> + <string name="notification_note_text">Observações (Máximo de 140 caracteres):</string> + + <string name="notification_alert">Atendimento está próximo</string> + </resources> -- GitLab From 947a48ee6da085bce38114bac19f0a504b3a2132 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Fri, 22 Dec 2017 11:35:53 -0200 Subject: [PATCH 3/9] AGILE#271: [WP] Cancel notification on logout, Show android notification Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- .../agendador/agendador/LoginActivity.java | 1 + .../agendador/ScheduleInfoActivity.java | 47 ++++++++++++------- .../agendador/SchedulesActivity.java | 8 ++-- .../agendador/SchedulesHistoryActivity.java | 2 +- .../agendador/agendador/helpers/Utils.java | 2 + .../agendador/models/CheckSchedules.java | 2 +- .../agendador/agendador/network/ApiUtils.java | 4 +- .../agendador/presenters/BasePresenter.java | 46 ++++++++++++++++-- .../agendador/services/BootReceiver.java | 2 +- .../LocalNotificationManager.java | 8 ++-- .../notification/NotificationReceiver.java | 9 +++- 11 files changed, 96 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java index 1842ca2..a33a5ea 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java @@ -205,6 +205,7 @@ public class LoginActivity extends AppCompatActivity implements LoginView { @Override public void afterSuccessfulLogin() { + // TODO 22/12/2017: instanciar job que verifica notificações no back-end. Intent intent = new Intent(LoginActivity.this, HomeActivity.class); startActivity(intent); finish(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java index 5c8a910..61a4a55 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java @@ -43,12 +43,15 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio private long id; - private CheckSchedules.Schedule schedule; private static final String EXIT_CONFIRMATION_DIALOG_TAG = "exit_dialog"; private int caller; + private TextView tv_name, tv_sector, tv_location, tv_type, + tv_date, tv_address, tv_situation, tv_situation_content; + + @Override protected void onCreate(Bundle savedInstanceState) { @@ -114,29 +117,25 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio } }); + tv_name = (TextView) findViewById(R.id.tv_schedule_citizen_content); + tv_sector = (TextView) findViewById(R.id.tv_schedule_sector_content); + tv_location = (TextView) findViewById(R.id.tv_schedule_location_content); + tv_type = (TextView) findViewById(R.id.tv_schedule_type_content); + tv_date = (TextView) findViewById(R.id.tv_schedule_date_content); + tv_address = (TextView) findViewById(R.id.tv_schedule_street_content); + tv_situation = (TextView) findViewById(R.id.tv_schedule_situation); + tv_situation_content = (TextView) findViewById(R.id.tv_schedule_situation_content); + + id = getIntent().getIntExtra(Utils.ID, 0); Bundle bundle = getIntent().getBundleExtra(Utils.SCHEDULE_BUNDLE); + CheckSchedules.Schedule schedule = null; if(bundle != null){ - DateFormat df = new SimpleDateFormat("dd/MM/yyyy - HH:mm", Locale.getDefault()); String name = bundle.getString(Utils.NAME); id = bundle.getLong(Utils.ID); schedule = bundle.getParcelable(Utils.SCHEDULE); - TextView tv_name = (TextView) findViewById(R.id.tv_schedule_citizen_content); - TextView tv_sector = (TextView) findViewById(R.id.tv_schedule_sector_content); - TextView tv_location = (TextView) findViewById(R.id.tv_schedule_location_content); - TextView tv_type = (TextView) findViewById(R.id.tv_schedule_type_content); - TextView tv_date = (TextView) findViewById(R.id.tv_schedule_date_content); - TextView tv_address = (TextView) findViewById(R.id.tv_schedule_street_content); - TextView tv_situation = (TextView) findViewById(R.id.tv_schedule_situation); - TextView tv_situation_content = (TextView) findViewById(R.id.tv_schedule_situation_content); - tv_name.setText(name); - tv_sector.setText(schedule.getSectorName()); - tv_location.setText(schedule.getLocationName()); - tv_type.setText(schedule.getServiceTypeName()); - tv_date.setText(df.format(schedule.getStartTime())); - String address = schedule.getAddressStreet() + ", " + schedule.getAddressNumber(); - tv_address.setText(address); + showScheduleContent(schedule); caller = bundle.getInt(Utils.CALLER_ACTIVITY); if(caller == Utils.SCHEDULES_ACTIVITY){ @@ -147,6 +146,10 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio navigationView.setCheckedItem(R.id.nav_schedules_history); tv_situation_content.setText(schedule.getSituation()); } + }else if(id != 0 ){ + //pega schedule + // TODO: caso a intent veio da notificação, realizar requisição para pegar os dados. + //showScheduleContent(schedule); } @@ -163,6 +166,16 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio } + private void showScheduleContent(CheckSchedules.Schedule schedule){ + DateFormat df = new SimpleDateFormat("dd/MM/yyyy - HH:mm", Locale.getDefault()); + tv_sector.setText(schedule.getSectorName()); + tv_location.setText(schedule.getLocationName()); + tv_type.setText(schedule.getServiceTypeName()); + tv_date.setText(df.format(schedule.getStartTime())); + String address = schedule.getAddressStreet() + ", " + schedule.getAddressNumber(); + tv_address.setText(address); + } + @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { Intent intent; diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java index 904dde0..c101916 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesActivity.java @@ -250,9 +250,9 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi maxDate = new Date(); String date; - if(schedules.getSchedules().getSchedulesList() != null) { + if(schedules.getSchedulesModel().getSchedulesList() != null) { - for (CheckSchedules.Schedule schedule : schedules.getSchedules().getSchedulesList()) { + for (CheckSchedules.Schedule schedule : schedules.getSchedulesModel().getSchedulesList()) { date = dateFormat.format(schedule.getStartTime()); if(schedule.getStartTime().after(maxDate)){ maxDate = schedule.getStartTime(); @@ -414,8 +414,8 @@ public class SchedulesActivity extends AppCompatActivity implements NavigationVi long id = 0; //searching if this schedule belongs to the citizen or the dependents. - for(int i = 0; i < schedules.getSchedules().getSchedulesList().size() && id == 0; ++i){ - if(schedules.getSchedules().getSchedulesList().get(i).getId() == selectedSchedule.getId()) + for(int i = 0; i < schedules.getSchedulesModel().getSchedulesList().size() && id == 0; ++i){ + if(schedules.getSchedulesModel().getSchedulesList().get(i).getId() == selectedSchedule.getId()) { id = schedules.getId(); name = schedules.getName(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java index 79e0272..aa2aea8 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/SchedulesHistoryActivity.java @@ -756,7 +756,7 @@ public class SchedulesHistoryActivity extends AppCompatActivity implements Navig expandableListTitle = new ArrayList<>(); expandableListTitle.add(new Pair<>(schedules.getName(), schedules.getId())); - expandableListDetail.put(schedules.getName(), schedules.getSchedules().getSchedulesList()); + expandableListDetail.put(schedules.getName(), schedules.getSchedulesModel().getSchedulesList()); for (CheckSchedules.DependentSchedules dependentSchedules : schedules.getDependentSchedulesList()) { expandableListTitle.add(new Pair<>(dependentSchedules.getName(), dependentSchedules.getId())); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java index 058d842..d5ddd96 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java @@ -127,6 +127,8 @@ public abstract class Utils { public static final String ACTION_SHOW_NOTIFICATION = "br.ufpr.c3sl.agendador.SHOW_NOTIFICATION"; + public static final int SHOW_SCHEDULE_INFO_ACTION = 0x11; + public static int getPixelValue(int dp, Context context) { Resources resources = context.getResources(); return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java index 2dc9b0a..ad994dd 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/CheckSchedules.java @@ -41,7 +41,7 @@ public class CheckSchedules { this.dependentSchedulesList = dependentSchedulesList; } - public ScheduleListModel getSchedules() { + public ScheduleListModel getSchedulesModel() { return schedules; } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java index c4d09fd..8e35b85 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiUtils.java @@ -14,8 +14,8 @@ import retrofit2.converter.gson.GsonConverterFactory; */ public abstract class ApiUtils { -// public static final String BASE_URL = "http://10.0.2.2:3000/v1/"; - public static final String BASE_URL = "http://newcastle.c3sl.ufpr.br/develop/v1/"; + public static final String BASE_URL = "http://10.0.2.2:3000/v1/"; +// public static final String BASE_URL = "http://newcastle.c3sl.ufpr.br/develop/v1/"; public static ApiEndpoints request(final Map<String, String> header) { OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java index 15b6e51..f823665 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java @@ -1,19 +1,31 @@ package br.ufpr.c3sl.agendador.agendador.presenters; +import android.app.AlarmManager; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.support.annotation.NonNull; +import android.util.Log; import com.firebase.jobdispatcher.FirebaseJobDispatcher; import com.firebase.jobdispatcher.GooglePlayDriver; +import com.google.gson.Gson; import java.lang.ref.WeakReference; +import java.util.List; 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.services.notification.LocalNotificationManager; +import br.ufpr.c3sl.agendador.agendador.services.notification.NotificationReceiver; import okhttp3.Headers; +import static android.content.Context.ALARM_SERVICE; + /** * Created by Bruno Freitas Tissei on 2/2/17. */ @@ -55,7 +67,7 @@ public abstract class BasePresenter<V> { protected void updateHeaders(Headers headers) { if(osb == null && context != null) - osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE);; + osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE); if(headers.get(Utils.ACCESS_TOKEN) != null) osb.edit().putString(Utils.ACCESS_TOKEN, headers.get(Utils.ACCESS_TOKEN)).apply(); @@ -73,11 +85,37 @@ public abstract class BasePresenter<V> { dispatcher.cancel(Utils.SERVICE_UPDATE_IMAGE); + if(osb == null) + osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE); + + Gson gson = new Gson(); + + List<Notification> notificationList = LocalNotificationManager.getList(osb, gson); + + Intent intent = new Intent(context, NotificationReceiver.class); + intent.setAction(Utils.ACTION_SHOW_NOTIFICATION); + + PendingIntent pendingIntent; + AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE); + + + for(Notification n : notificationList){ + + pendingIntent = PendingIntent.getBroadcast(context, + LocalNotificationManager.NOTIFICATION_REMINDER_REQUEST_CODE + (int) n.scheduleId, intent, + PendingIntent.FLAG_CANCEL_CURRENT); + + if(am != null){ + am.cancel(pendingIntent); + } + + } + osb.edit().clear().apply(); - Intent intent = new Intent(context, LoginActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + Intent intent2 = new Intent(context, LoginActivity.class); + intent2.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent2); } } \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java index 1786d10..9262670 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/BootReceiver.java @@ -55,7 +55,7 @@ public class BootReceiver extends BroadcastReceiver { try { date = sdfServer.parse(notification.reminderTime); calendar.setTime(date); - LocalNotificationManager.setReminder(context, NotificationReceiver.class, calendar, (int) notification.scheduleId); + LocalNotificationManager.setReminder(context, calendar, (int) notification.scheduleId); } catch (ParseException e) { e.printStackTrace(); } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java index e463eba..3d8fc1f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java @@ -34,7 +34,7 @@ import static android.content.Context.ALARM_SERVICE; public abstract class LocalNotificationManager { - private static final int NOTIFICATION_REMINDER_REQUEST_CODE = 0x27; + public static final int NOTIFICATION_REMINDER_REQUEST_CODE = 0x27; public static void createLocalNotification(Context context, Notification notification, ObscuredSharedPreferences osb, Gson gson){ @@ -45,7 +45,7 @@ public abstract class LocalNotificationManager { try{ calendar.setTime(sdfServer.parse(notification.reminderTime)); - setReminder(context, NotificationReceiver.class, calendar, (int) notification.scheduleId); + setReminder(context, calendar, (int) notification.scheduleId); }catch (ParseException ignored){ Log.e("Agendador", "Erro ao parsear data, para criar notificação local."); ignored.printStackTrace(); @@ -53,9 +53,9 @@ public abstract class LocalNotificationManager { } - public static void setReminder(Context context, Class<?> cls, Calendar calendar, int scheduleId){ + public static void setReminder(Context context, Calendar calendar, int scheduleId){ - Intent intent = new Intent(context, cls); + Intent intent = new Intent(context, NotificationReceiver.class); intent.setAction(Utils.ACTION_SHOW_NOTIFICATION); intent.putExtra(Utils.ID, scheduleId); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java index 326f2fe..f5d294f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java @@ -1,6 +1,7 @@ package br.ufpr.c3sl.agendador.agendador.services.notification; import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -14,6 +15,7 @@ import com.google.gson.Gson; import java.util.List; 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; @@ -53,10 +55,15 @@ public class NotificationReceiver extends BroadcastReceiver{ NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context); + Intent showScheduleIntent = new Intent(context, ScheduleInfoActivity.class); + showScheduleIntent.putExtra(Utils.ID, id); + + PendingIntent pendingIntent = PendingIntent.getActivity(context, Utils.SHOW_SCHEDULE_INFO_ACTION, showScheduleIntent, PendingIntent.FLAG_UPDATE_CURRENT); + String alert = context.getResources().getString(R.string.notification_alert); android.app.Notification appNotification = mBuilder.setAutoCancel(true).setContentText(content.description).setContentTitle(alert) .setDefaults(android.app.Notification.DEFAULT_LIGHTS | android.app.Notification.DEFAULT_SOUND) - .setSmallIcon(R.drawable.img_mainact_logo).setTicker(alert) + .setSmallIcon(R.drawable.img_mainact_logo).setTicker(alert).setContentIntent(pendingIntent) .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.img_terms_logo)).build(); // Will display the notification in the notification bar -- GitLab From 0f5cdf5884c3c398c78de6708bcc50347145f1f5 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Wed, 17 Jan 2018 09:28:41 -0200 Subject: [PATCH 4/9] AGILE#301: Issue completed Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- .../ScheduleConfirmationActivity.java | 6 +- .../agendador/ScheduleInfoActivity.java | 114 ++++++++++++--- .../agendador/models/ScheduleInfo.java | 131 ++++++++++++++++++ .../agendador/models/ShortAddress.java | 32 +++++ .../agendador/network/ApiEndpoints.java | 4 +- .../presenters/ScheduleInfoPresenter.java | 97 +++++++++++++ .../LocalNotificationManager.java | 5 +- .../agendador/views/ScheduleInfoView.java | 18 +++ .../main/res/layout/content_schedule_info.xml | 9 ++ 9 files changed, 393 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleInfo.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ShortAddress.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleInfoPresenter.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleInfoView.java diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java index 885780f..dfb421c 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java @@ -257,7 +257,7 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S }); if(savedInstanceState == null){ - scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(getBaseContext()); + scheduleConfirmationPresenter = new ScheduleConfirmationPresenter(this); }else{ scheduleConfirmationPresenter = PresenterManager.getInstance().restorePresenter(savedInstanceState); if(scheduleConfirmationPresenter == null) @@ -387,7 +387,8 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S schedule.getLocationName(), schedule.getAddressStreet(), schedule.getAddressNumber(), sdfDate.format(schedule.getStartTime()), sdfHour.format(schedule.getStartTime())); - notification.reminderTime = sdfServer.format(schedule.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()])); + // TODO: 15/01/18 Apagar aqui o tempo a mais que está sendo usado no calculo da notificaçõa, está em dobro. + 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(); @@ -443,7 +444,6 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S bt_schedule.setEnabled(true); bt_back.setEnabled(true); } - } @Override diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java index 61a4a55..d120503 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java @@ -20,6 +20,7 @@ import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.ImageView; +import android.widget.ProgressBar; import android.widget.TextView; import org.w3c.dom.Text; @@ -28,12 +29,17 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Locale; +import br.ufpr.c3sl.agendador.agendador.helpers.ConnectionErrorDialog; import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; import br.ufpr.c3sl.agendador.agendador.helpers.UserImgHelper; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; import br.ufpr.c3sl.agendador.agendador.models.CheckSchedules; +import br.ufpr.c3sl.agendador.agendador.presenters.PresenterManager; +import br.ufpr.c3sl.agendador.agendador.presenters.ScheduleConfirmationPresenter; +import br.ufpr.c3sl.agendador.agendador.presenters.ScheduleInfoPresenter; +import br.ufpr.c3sl.agendador.agendador.views.ScheduleInfoView; -public class ScheduleInfoActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{ +public class ScheduleInfoActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, ScheduleInfoView{ private MenuBuilder menuBuilder; @@ -43,7 +49,6 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio private long id; - private static final String EXIT_CONFIRMATION_DIALOG_TAG = "exit_dialog"; private int caller; @@ -51,7 +56,15 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio private TextView tv_name, tv_sector, tv_location, tv_type, tv_date, tv_address, tv_situation, tv_situation_content; + private ScheduleInfoPresenter presenter; + + private ConnectionErrorDialog connectionErrorDialog; + + private Button bt_back; + private ProgressBar pb_scheduleInfo; + + private boolean hasToRequest; @Override protected void onCreate(Bundle savedInstanceState) { @@ -125,17 +138,39 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio tv_address = (TextView) findViewById(R.id.tv_schedule_street_content); tv_situation = (TextView) findViewById(R.id.tv_schedule_situation); tv_situation_content = (TextView) findViewById(R.id.tv_schedule_situation_content); + pb_scheduleInfo = (ProgressBar) findViewById(R.id.pb_schedule_info); + bt_back = (Button) findViewById(R.id.btn_schedule_info_back); + bt_back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); id = getIntent().getIntExtra(Utils.ID, 0); + + if(savedInstanceState == null){ + presenter = new ScheduleInfoPresenter(this); + }else{ + presenter = PresenterManager.getInstance().restorePresenter(savedInstanceState); + if(presenter == null) { + presenter = new ScheduleInfoPresenter(this); + } + } + + + Bundle bundle = getIntent().getBundleExtra(Utils.SCHEDULE_BUNDLE); CheckSchedules.Schedule schedule = null; - if(bundle != null){ + + hasToRequest = true; + if(bundle != null && bundle.getParcelable(Utils.SCHEDULE) != null){ String name = bundle.getString(Utils.NAME); id = bundle.getLong(Utils.ID); schedule = bundle.getParcelable(Utils.SCHEDULE); tv_name.setText(name); - showScheduleContent(schedule); + showScheduleContent(schedule, null); caller = bundle.getInt(Utils.CALLER_ACTIVITY); if(caller == Utils.SCHEDULES_ACTIVITY){ @@ -146,27 +181,32 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio navigationView.setCheckedItem(R.id.nav_schedules_history); tv_situation_content.setText(schedule.getSituation()); } - }else if(id != 0 ){ - //pega schedule - // TODO: caso a intent veio da notificação, realizar requisição para pegar os dados. - //showScheduleContent(schedule); + hasToRequest = false; } - navigationView.setNavigationItemSelectedListener(this); - Button bt_back = (Button) findViewById(R.id.btn_schedule_info_back); - bt_back.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onBackPressed(); - } - }); } - private void showScheduleContent(CheckSchedules.Schedule schedule){ + @Override + protected void onPause() { + super.onPause(); + presenter.unbindView(); + } + + @Override + protected void onResume() { + super.onResume(); + presenter.bindView(this); + if(hasToRequest && id != 0 ){ + presenter.requestScheduleInfo(id); + } + } + + // TODO: 16/01/18 extract date pattern to utils class + public void showScheduleContent(CheckSchedules.Schedule schedule, String citizenName){ DateFormat df = new SimpleDateFormat("dd/MM/yyyy - HH:mm", Locale.getDefault()); tv_sector.setText(schedule.getSectorName()); tv_location.setText(schedule.getLocationName()); @@ -174,6 +214,10 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio tv_date.setText(df.format(schedule.getStartTime())); String address = schedule.getAddressStreet() + ", " + schedule.getAddressNumber(); tv_address.setText(address); + tv_situation_content.setText(schedule.getSituation()); + if(citizenName != null && !citizenName.equals("")){ + tv_name.setText(citizenName); + } } @Override @@ -232,6 +276,42 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio } } + @Override + public void setProgressBar(boolean enabled) { + if (enabled) { + pb_scheduleInfo.setVisibility(View.VISIBLE); + } else { + pb_scheduleInfo.setVisibility(View.INVISIBLE); + } + bt_back.setEnabled(!enabled); + } + + @Override + public void setConnectionError(boolean enabled) { + if(enabled){ + if(connectionErrorDialog == null){ + connectionErrorDialog = new ConnectionErrorDialog(); + } + Bundle bundle = new Bundle(); + bundle.putString(ConnectionErrorDialog.DIALOG_MESSAGE, getString(R.string.dialog_connection_error_message)); + connectionErrorDialog.setArguments(bundle); + connectionErrorDialog.show(getFragmentManager(), ConnectionErrorDialog.DIALOG_CONNECTION_ERROR); + } + } + + @Override + public void setNoConnection(boolean enabled) { + if(enabled){ + if(connectionErrorDialog == null){ + connectionErrorDialog = new ConnectionErrorDialog(); + } + Bundle bundle = new Bundle(); + bundle.putString(ConnectionErrorDialog.DIALOG_MESSAGE, getString(R.string.dialog_connection_error_message)); + connectionErrorDialog.setArguments(bundle); + connectionErrorDialog.show(getFragmentManager(), ConnectionErrorDialog.DIALOG_CONNECTION_ERROR); + } + } + public static class ConfirmationDialogFragment extends DialogFragment { @NonNull @Override diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleInfo.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleInfo.java new file mode 100644 index 0000000..5c114d7 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleInfo.java @@ -0,0 +1,131 @@ +package br.ufpr.c3sl.agendador.agendador.models; + +import com.google.gson.annotations.SerializedName; + +import java.util.Date; + +/** + * Created by Lucas Braz Cunha on 16/01/18. + * + * model to receive request schedules/{id_schdule}?permission=citizen + * + * with complete schedule information. + */ + +public class ScheduleInfo { + + @SerializedName("citizen_data") + CitizenSchedule citizen; + + @SerializedName("service_place_data") + ServicePlaceSchedule servicePlace; + + @SerializedName("schedule_data") + ScheduleData schedule; + + + public long getId(){ + return citizen.id; + } + + public Date getStartTime(){ + return schedule.startTime; + } + + public String getSectorName(){ + return schedule.sectorName; + } + + public String getServiceTypeName(){ + return schedule.serviceTypeName; + } + + public String getLocationName(){ + return servicePlace.name; + } + + public String getAddressStreet(){ + return servicePlace.address.address; + } + + public String getAddressNumber(){ + return servicePlace.number; + } + + public String getSituation(){ + return schedule.situation; + } + + public String getCitizenName(){ + return citizen.name; + } + + + public static class CitizenSchedule{ + + @SerializedName("id") + long id; + + @SerializedName("name") + String name; + + @SerializedName("birth_date") + String birthDate; + + @SerializedName("rg") + String rg; + + @SerializedName("cpf") + String cpf; + + @SerializedName("note") + String note; + + } + + public static class ServicePlaceSchedule{ + + + @SerializedName("name") + String name; + + @SerializedName("complement") + String complement; + + @SerializedName("phone1") + String phone; + + @SerializedName("address_number") + String number; + + @SerializedName("address") + ShortAddress address; + + } + + public static class ScheduleData{ + + @SerializedName("id") + long id; + + @SerializedName("service_type_name") + String serviceTypeName; + + @SerializedName("service_start_time") + Date startTime; + + @SerializedName("professional_performer") + String professionalName; + + @SerializedName("situation") + String situation; + + @SerializedName("sector_name") + String sectorName; + + @SerializedName("sector_id") + long sectorId; + + } + +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ShortAddress.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ShortAddress.java new file mode 100644 index 0000000..7542ad0 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ShortAddress.java @@ -0,0 +1,32 @@ +package br.ufpr.c3sl.agendador.agendador.models; + +import com.google.gson.annotations.SerializedName; + +/** + * Created by Lucas Braz Cunha on 16/01/18. + * + * model for request: schedules/{id_schedule}?permission=citizen + * + * + */ + +public class ShortAddress { + + @SerializedName("id") + long id; + + @SerializedName("zipcode") + String zipcode; + + @SerializedName("address") + String address; + + @SerializedName("neighborhood") + String neighborhood; + + @SerializedName("complement") + String complement; + + @SerializedName("complement2") + String complement2; +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java index 0683147..58aea69 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java @@ -17,6 +17,7 @@ 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.ScheduleConfirmation; +import br.ufpr.c3sl.agendador.agendador.models.ScheduleInfo; import br.ufpr.c3sl.agendador.agendador.models.ScheduleNote; import br.ufpr.c3sl.agendador.agendador.models.SectorInput; import br.ufpr.c3sl.agendador.agendador.models.ServicePlace; @@ -95,5 +96,6 @@ public interface ApiEndpoints { @POST("notifications?permission=2") Call<NotificationReturn> requestCreateNotification(@Body Notification notification); - + @GET("schedules/{id_schedule}?permission=citizen") + Call<ScheduleInfo> requestScheduleInfo(@Path("id_schedule") long id); } \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleInfoPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleInfoPresenter.java new file mode 100644 index 0000000..44dddc6 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleInfoPresenter.java @@ -0,0 +1,97 @@ +package br.ufpr.c3sl.agendador.agendador.presenters; + +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; + +import br.ufpr.c3sl.agendador.agendador.ScheduleInfoActivity; +import br.ufpr.c3sl.agendador.agendador.SchedulesActivity; +import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; +import br.ufpr.c3sl.agendador.agendador.helpers.Utils; +import br.ufpr.c3sl.agendador.agendador.models.CheckSchedules; +import br.ufpr.c3sl.agendador.agendador.models.ScheduleInfo; +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 15/01/18. + */ + +public class ScheduleInfoPresenter extends BasePresenter<ScheduleInfoActivity> { + + private ScheduleInfoPresenter presenter; + + public ScheduleInfoPresenter(Context context) { + this.context = context; + presenter = this; + osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE); + } + + + + public void requestScheduleInfo(long id){ + Map<String, String> header = new HashMap<>(); + 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)); + + final ApiEndpoints service = ApiUtils.request(header); + Call<ScheduleInfo> listCall = service.requestScheduleInfo(id); + + presenter.view().setProgressBar(true); + listCall.enqueue(new Callback<ScheduleInfo>() { + + @Override + public void onResponse(Call<ScheduleInfo> call, Response<ScheduleInfo> response) { + Headers headers = response.headers(); + int status = response.code(); + ScheduleInfo scheduleInfo = response.body(); + updateHeaders(headers); + switch (status) { + case 200: + CheckSchedules.Schedule schedule = new CheckSchedules.Schedule(scheduleInfo.getId(), scheduleInfo.getStartTime(), + scheduleInfo.getSectorName(), + scheduleInfo.getServiceTypeName(), scheduleInfo.getLocationName(), + scheduleInfo.getAddressStreet(), scheduleInfo.getAddressNumber(), + scheduleInfo.getSituation()); + Log.d("Server response", getClass().getName() + ": 200 - Sucesso!"); + presenter.view().showScheduleContent(schedule,scheduleInfo.getCitizenName()); + presenter.view().setProgressBar(false); + break; + default: + Log.e("Server response", getClass().getName() + ": ERRO:" + status); + Log.v("Server response", "Redirecionando para tela de visualizar agendamentos."); + Intent i = new Intent(context, SchedulesActivity.class); + i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + presenter.view().finish(); + context.startActivity(i); + break; + } + + } + + @Override + public void onFailure(Call<ScheduleInfo> call, Throwable t) { + Log.e("Server response", getClass().getName() + ": Requisição falhou!!"); + presenter.view().setProgressBar(false); + presenter.view().setNoConnection(true); + t.printStackTrace(); + } + }); + + } + + + @Override + protected void updateView() { + + } +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java index 3d8fc1f..26175cb 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java @@ -30,7 +30,6 @@ import static android.content.Context.ALARM_SERVICE; */ - public abstract class LocalNotificationManager { @@ -98,7 +97,9 @@ public abstract class LocalNotificationManager { // 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, ""); - return gson.fromJson(jsonList, new TypeToken<List<Notification>>(){}.getType()); + List<Notification> notifications = gson.fromJson(jsonList, new TypeToken<List<Notification>>(){}.getType()); + + return notifications == null ? new ArrayList<Notification>() : notifications; } // TODO: 15/12/17 Testar o remove. diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleInfoView.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleInfoView.java new file mode 100644 index 0000000..eaee154 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleInfoView.java @@ -0,0 +1,18 @@ +package br.ufpr.c3sl.agendador.agendador.views; + +import br.ufpr.c3sl.agendador.agendador.models.CheckSchedules; + +/** + * Created by Lucas B. Cunha on 15/01/18. + */ + +public interface ScheduleInfoView { + + void setProgressBar(boolean enabled); + + void setConnectionError(boolean enabled); + + void setNoConnection(boolean enabled); + + void showScheduleContent(CheckSchedules.Schedule schedule, String citizenName); +} diff --git a/app/src/main/res/layout/content_schedule_info.xml b/app/src/main/res/layout/content_schedule_info.xml index 2d07ab0..d459fc1 100644 --- a/app/src/main/res/layout/content_schedule_info.xml +++ b/app/src/main/res/layout/content_schedule_info.xml @@ -242,4 +242,13 @@ </LinearLayout> + <ProgressBar + android:layout_width="80dp" + android:id="@+id/pb_schedule_info" + android:layout_height="80dp" + android:layout_centerHorizontal="true" + android:layout_centerVertical="true" + android:indeterminate="true" + android:visibility="invisible" /> + </RelativeLayout> \ No newline at end of file -- GitLab From ff00deb7796bb6905442140fb5eba7e852ac3cd9 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Fri, 19 Jan 2018 12:10:31 -0200 Subject: [PATCH 5/9] AGILE#307: [WP] Implementing service to update local list of notifications Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- app/src/main/AndroidManifest.xml | 9 + .../agendador/agendador/LoginActivity.java | 34 +++- .../ScheduleConfirmationActivity.java | 5 +- .../agendador/ScheduleInfoActivity.java | 5 +- .../agendador/agendador/helpers/Utils.java | 1 + .../agendador/network/ApiEndpoints.java | 4 + .../agendador/presenters/BasePresenter.java | 2 +- .../ScheduleConfirmationPresenter.java | 7 +- .../NotificationCreateService.java | 82 +++++---- .../notification/NotificationReceiver.java | 1 + .../NotificationsListService.java | 156 ++++++++++++++++++ app/src/main/res/values/strings.xml | 2 +- 12 files changed, 262 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ef2648c..075728c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,6 +58,15 @@ </intent-filter> </service> + <service + android:name=".services.notification.NotificationsListService" + android:exported="false" + android:permission="android.permission.BIND_JOB_SERVICE"> + <intent-filter> + <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" /> + </intent-filter> + </service> + <receiver android:name=".services.BootReceiver"> <intent-filter> diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java index a33a5ea..447474a 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java @@ -12,6 +12,7 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.TextWatcher; import android.text.style.StyleSpan; +import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; @@ -19,6 +20,14 @@ import android.widget.ProgressBar; import android.widget.TextView; 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 java.io.IOException; import br.ufpr.c3sl.agendador.agendador.helpers.ConnectionChecker; @@ -28,6 +37,7 @@ import br.ufpr.c3sl.agendador.agendador.helpers.UserImgHelper; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; import br.ufpr.c3sl.agendador.agendador.presenters.LoginPresenter; import br.ufpr.c3sl.agendador.agendador.presenters.PresenterManager; +import br.ufpr.c3sl.agendador.agendador.services.notification.NotificationsListService; import br.ufpr.c3sl.agendador.agendador.views.LoginView; /** @@ -205,7 +215,29 @@ public class LoginActivity extends AppCompatActivity implements LoginView { @Override public void afterSuccessfulLogin() { - // TODO 22/12/2017: instanciar job que verifica notificações no back-end. + FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher( + new GooglePlayDriver(this) + ); + + Job job = dispatcher.newJobBuilder() + .setService(NotificationsListService.class) + .setTag(Utils.NOTIFICATION_UPDATE_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)) + //will be retried if it fails. + .setRecurring(true) + .setRetryStrategy(RetryStrategy.DEFAULT_LINEAR) + .setConstraints( + // only run on network + Constraint.ON_ANY_NETWORK + ) + //if device is rebooted the job will be restarted + .setLifetime(Lifetime.FOREVER) + .build(); + dispatcher.mustSchedule(job); + Log.d("AGNDDR-NotifiUpdate", "Job agendado para atualizar lista de coisas"); + Intent intent = new Intent(LoginActivity.this, HomeActivity.class); startActivity(intent); finish(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java index dfb421c..7524005 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java @@ -383,9 +383,8 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S notification.scheduleId = schedule.getId(); notification.emailSent = false; - notification.description = getResources().getString(R.string.notification_content, schedule.getServiceTypeName(), - schedule.getLocationName(), schedule.getAddressStreet(), schedule.getAddressNumber(), - sdfDate.format(schedule.getStartTime()), sdfHour.format(schedule.getStartTime())); + notification.description = getResources().getString(R.string.notification_content, sdfDate.format(schedule.getStartTime()), sdfHour.format(schedule.getStartTime()), schedule.getServiceTypeName(), + schedule.getLocationName(), schedule.getAddressStreet(), schedule.getAddressNumber()); // TODO: 15/01/18 Apagar aqui o tempo a mais que está sendo usado no calculo da notificaçõa, está em dobro. notification.reminderTime = sdfServer.format(schedule.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()]) - (reminderTimeArray[sp_notification.getSelectedItemPosition()])); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java index d120503..5128565 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleInfoActivity.java @@ -322,9 +322,8 @@ public class ScheduleInfoActivity extends AppCompatActivity implements Navigatio builder.setMessage(R.string.signout_confirmation) .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - SchedulesActivity activity = (SchedulesActivity) getActivity(); - // TODO: 05/10/17 fix here - //activity.presenter.onSignOutClicked(); + ScheduleInfoActivity activity = (ScheduleInfoActivity) getActivity(); + activity.presenter.onSignOutClicked(); } }) .setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() { diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java index d5ddd96..91608ab 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java @@ -122,6 +122,7 @@ 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_LIST = "notification_list"; diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java index 58aea69..1c35a04 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java @@ -98,4 +98,8 @@ public interface ApiEndpoints { @GET("schedules/{id_schedule}?permission=citizen") Call<ScheduleInfo> requestScheduleInfo(@Path("id_schedule") long id); + + @GET("notifications?permission=citizen") + Call<List<NotificationReturn>> requestNotifications(); + } \ No newline at end of file diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java index f823665..6be7a1d 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java @@ -77,13 +77,13 @@ public abstract class BasePresenter<V> { 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(); - } public void onSignOutClicked() { FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context)); dispatcher.cancel(Utils.SERVICE_UPDATE_IMAGE); + dispatcher.cancel(Utils.NOTIFICATION_UPDATE_SERVICE); if(osb == null) osb = ObscuredSharedPreferences.getPrefs(context, "Agendador", Context.MODE_PRIVATE); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java index b9f086e..3f9baa2 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java @@ -113,7 +113,7 @@ 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>() { @@ -162,11 +162,10 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm Job job = dispatcher.newJobBuilder() .setService(NotificationCreateService.class) - .setTag(Utils.NOTIFICATION_SERVICE) + .setTag(Utils.NOTIFICATION_SERVICE + notification.scheduleId) //time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600 - .setTrigger(Trigger.executionWindow(10, 3600)) + .setTrigger(Trigger.NOW) //will be retried if it fails. - .setRecurring(true) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) .setConstraints( // only run on network diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java index 273300a..075d8be 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java @@ -9,6 +9,7 @@ import com.firebase.jobdispatcher.JobService; import com.google.gson.Gson; import java.util.HashMap; +import java.util.List; import java.util.Map; import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; @@ -32,54 +33,58 @@ public class NotificationCreateService extends JobService { @Override public boolean onStartJob(final JobParameters job) { Log.v("AGNDDR-NotifiCreate", "Rodando " + NotificationCreateService.class.getName()); - ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(getBaseContext(), "Agendador", Context.MODE_PRIVATE); - final Bundle extras = job.getExtras(); - Map<String, String> header = new HashMap<>(); - final String uid = osb.getString(Utils.UID, null); - 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.ID, uid); + new Thread(new Runnable() { + public void run() { - Notification notification = null; + final Bundle extras = job.getExtras(); + 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)); - if (extras != null) { - notification = new Gson().fromJson(extras.getString(Utils.NOTIFICATION), Notification.class); - }else{ - Log.e("AGNDDR-NotifiCreate", "Job não recebeu os extras."); - jobFinished(job, true); - } + Notification notification = null; - ApiEndpoints service = ApiUtils.request(header); + if (extras != null) { + notification = new Gson().fromJson(extras.getString(Utils.NOTIFICATION), Notification.class); + } else { + Log.e("AGNDDR-NotifiCreate", "Job não recebeu os extras."); + jobFinished(job, true); + } + + requestCreateNotification(header, job, osb, notification); + + + }}).start(); + + return true; + } + + + private void requestCreateNotification(final Map<String, String> header, final JobParameters job, final ObscuredSharedPreferences osb, final Notification notification){ + + final ApiEndpoints service = ApiUtils.request(header); Call<NotificationReturn> listCall = service.requestCreateNotification(notification); - final Notification finalNotification = notification; listCall.enqueue(new Callback<NotificationReturn>() { @Override public void onResponse(Call<NotificationReturn> call, Response<NotificationReturn> response) { - int status = response.code(); Headers headers = response.headers(); - ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(getBaseContext(), "Agendador", Context.MODE_PRIVATE); - - 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(); - + int status = response.code(); + updateHeaders(headers, osb); switch (status) { case 200: - LocalNotificationManager.createLocalNotification(getApplicationContext(), finalNotification, osb, new Gson()); + case 201: + Log.d("Server response", getClass().getName() + ": 200 - Sucesso!"); + LocalNotificationManager.createLocalNotification(getApplicationContext(), notification, osb, new Gson()); jobFinished(job, false); break; default: - Log.v("AGNDDR-NotifiCreate", "Job foi executado mas recebeu retorno " + status); + Log.e("Server response", getClass().getName() + ": ERRO:" + status); jobFinished(job, true); break; } @@ -88,17 +93,28 @@ public class NotificationCreateService extends JobService { @Override public void onFailure(Call<NotificationReturn> call, Throwable t) { - Log.v("AGNDDR-NotifiCreate", "Job falhou e será remarcado!!"); + 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(); - return true; } + @Override public boolean onStopJob(JobParameters job) { return true; diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java index f5d294f..14b5d9f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java @@ -44,6 +44,7 @@ public class NotificationReceiver extends BroadcastReceiver{ 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); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java new file mode 100644 index 0000000..144bf8d --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java @@ -0,0 +1,156 @@ +package br.ufpr.c3sl.agendador.agendador.services.notification; + +import android.content.Context; +import android.os.Looper; +import android.util.Log; +import android.util.LongSparseArray; +import android.util.SparseArray; +import android.util.SparseLongArray; + +import com.firebase.jobdispatcher.JobParameters; +import com.firebase.jobdispatcher.JobService; +import com.google.gson.Gson; + +import java.util.HashMap; +import java.util.List; +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.Notification; +import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn; +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 B. Cunha on 17/01/18. + * + * Service to keep local list of notifications synchronized. + */ + +public class NotificationsListService extends JobService { + /** + * The entry point to your Job. Implementations should offload work to another thread of + * execution as soon as possible. + * + * @param job + * @return whether there is more work remaining. + */ + @Override + public boolean onStartJob(final JobParameters job) { + + Log.d("AGNDDR-NotifiUpdate", "Estou no Job"); + + + new Thread(new Runnable() { + public void run() { + + Log.v("AGNDDR-NotifiUpdate", "Rodando " + NotificationsListService.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)); + requestNotificationUpdate(header, job, osb); + } + + }).start(); + + return true; + } + + + private void requestNotificationUpdate(final Map<String, String> header, final JobParameters job, final ObscuredSharedPreferences osb){ + + final ApiEndpoints service = ApiUtils.request(header); + Log.v("AGNDDR-NotifiUpdate", Utils.ACCESS_TOKEN + osb.getString(Utils.ACCESS_TOKEN, "NADA")); + Log.v("AGNDDR-NotifiUpdate", Utils.CLIENT + osb.getString(Utils.CLIENT, "NADA")); + Log.v("AGNDDR-NotifiUpdate", Utils.UID + osb.getString(Utils.UID, "NADA")); + + + + Call<List<NotificationReturn>> listCall = service.requestNotifications(); + + listCall.enqueue(new Callback<List<NotificationReturn>>() { + + @Override + public void onResponse(Call<List<NotificationReturn>> call, Response<List<NotificationReturn>> response) { + Headers headers = response.headers(); + int status = response.code(); + updateHeaders(headers, osb); + final List<NotificationReturn> responseList = response.body(); + switch (status) { + case 200: + case 201: + Log.d("Server response", getClass().getName() + ": 200 - Sucesso!"); + new Thread(new Runnable() { + public void run() { + Gson gson = new Gson(); + LongSparseArray<Notification> localNotifications = new LongSparseArray<>(); + List<Notification> list = LocalNotificationManager.getList(osb, gson); + for(Notification n : list) + localNotifications.append(n.scheduleId, n); + + for(NotificationReturn nr : responseList){ + if(localNotifications.get(nr.scheduleId) == null){ + LocalNotificationManager.createLocalNotification(getApplicationContext(), + new Notification(nr.scheduleId, nr.reminderTime, nr.hasRead == 0, + nr.description, nr.emailAddres, nr.emailSent == 0), + osb, gson); + } + } + + jobFinished(job, false); + }}).start(); + break; + default: + Log.e("Server response", getClass().getName() + ": ERRO:" + status); + + jobFinished(job, false); + break; + } + + } + + @Override + public void onFailure(Call<List<NotificationReturn>> call, Throwable t) { + Log.e("Server response", getClass().getName() + ": Requisição falhou!!"); + t.printStackTrace(); + jobFinished(job, false); + } + }); + + } + + 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. + * + * @param job + * @return true if the job should be retried + * + */ + @Override + public boolean onStopJob(JobParameters job) { + return true; + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bf0e056..4940c74 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -222,7 +222,7 @@ <string name="not_valid_email">Digite um e-mail válido.</string> - <string name="notification_content">%s em %s (%s, %d) %s às %s</string> + <string name="notification_content">%s às %s, %s em %s (%s, %d)</string> <string name="notification_note_text">Observações (Máximo de 140 caracteres):</string> <string name="notification_alert">Atendimento está próximo</string> -- GitLab From 2632dbdfa7dba8714f74fc72a7842fd8e8ea9e37 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Thu, 25 Jan 2018 09:34:12 -0200 Subject: [PATCH 6/9] AGILE#307: Done service to update notification's status to read. Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- app/src/main/AndroidManifest.xml | 9 ++ .../agendador/agendador/LoginActivity.java | 2 +- .../ScheduleConfirmationActivity.java | 2 +- .../agendador/agendador/helpers/Utils.java | 3 +- .../agendador/models/Notification.java | 8 +- .../agendador/models/NotificationReturn.java | 53 +++++- .../agendador/models/NotificationUpdate.java | 34 ++++ .../agendador/network/ApiEndpoints.java | 5 + .../agendador/presenters/BasePresenter.java | 9 +- .../ScheduleConfirmationPresenter.java | 4 +- .../LocalNotificationManager.java | 85 +++++----- .../NotificationCreateService.java | 6 +- .../notification/NotificationReadService.java | 141 ++++++++++++++++ .../notification/NotificationReceiver.java | 152 +++++++++++++++--- .../NotificationsListService.java | 30 ++-- 15 files changed, 441 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationUpdate.java create mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReadService.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 075728c..ac0f7c6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -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" diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java index 447474a..ebe2a46 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java @@ -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)) diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java index 7524005..a07cf0a 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java @@ -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); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java index 91608ab..dee274f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/helpers/Utils.java @@ -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"; diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java index c43de20..be32a0f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/Notification.java @@ -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)); } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java index 022bcf3..7887795 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java @@ -1,12 +1,15 @@ 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); + } } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationUpdate.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationUpdate.java new file mode 100644 index 0000000..5283f28 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationUpdate.java @@ -0,0 +1,34 @@ +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; + + } + +} + diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java index 1c35a04..6d351fc 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java @@ -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 diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java index 6be7a1d..f93d6a0 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/BasePresenter.java @@ -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){ diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java index 3f9baa2..88e032b 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java @@ -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."); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java index 26175cb..6fdf7c1 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/LocalNotificationManager.java @@ -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(); + } } + + } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java index 075d8be..0620e9f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java @@ -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: diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReadService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReadService.java new file mode 100644 index 0000000..4a43b80 --- /dev/null +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReadService.java @@ -0,0 +1,141 @@ +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; + } +} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java index 14b5d9f..a84d08f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationReceiver.java @@ -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){ + Log.e("Notificacao", "Erro: notificação não encontrada"); + }else if(notificationManager == null){ + Log.e("Notificacao", "Erro: notification manager null"); + }else{ + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context); + + Intent showScheduleIntent = new Intent(context, ScheduleInfoActivity.class); + showScheduleIntent.putExtra(Utils.ID, id); - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context); + PendingIntent pendingIntent = PendingIntent.getActivity(context, Utils.SHOW_SCHEDULE_INFO_ACTION, showScheduleIntent, PendingIntent.FLAG_UPDATE_CURRENT); - Intent showScheduleIntent = new Intent(context, ScheduleInfoActivity.class); - showScheduleIntent.putExtra(Utils.ID, id); + String alert = context.getResources().getString(R.string.notification_alert); + android.app.Notification appNotification = mBuilder.setAutoCancel(true).setContentText(content.description).setContentTitle(alert) + .setDefaults(android.app.Notification.DEFAULT_LIGHTS | android.app.Notification.DEFAULT_SOUND) + .setSmallIcon(R.drawable.img_mainact_logo).setTicker(alert).setContentIntent(pendingIntent) + .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.img_terms_logo)).build(); - PendingIntent pendingIntent = PendingIntent.getActivity(context, Utils.SHOW_SCHEDULE_INFO_ACTION, showScheduleIntent, PendingIntent.FLAG_UPDATE_CURRENT); - String alert = context.getResources().getString(R.string.notification_alert); - android.app.Notification appNotification = mBuilder.setAutoCancel(true).setContentText(content.description).setContentTitle(alert) - .setDefaults(android.app.Notification.DEFAULT_LIGHTS | android.app.Notification.DEFAULT_SOUND) - .setSmallIcon(R.drawable.img_mainact_logo).setTicker(alert).setContentIntent(pendingIntent) - .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.img_terms_logo)).build(); - // Will display the notification in the notification bar - notificationManager.notify(id, appNotification); + requestNotificationUpdate(osb, content, context); + // Will display the notification in the notification bar + notificationManager.notify(id, appNotification); + + } } } + + + + private void requestNotificationUpdate(final ObscuredSharedPreferences osb, final NotificationReturn notificationReturn, final Context context){ + Map<String, String> header = new HashMap<>(); + 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)); + + final ApiEndpoints service = ApiUtils.request(header); + + + 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: + Log.d("Server response", getClass().getName() + ": 200 - Sucesso!"); + LocalNotificationManager.removeNotification(notificationReturn, osb, new Gson()); + break; + default: + Log.e("Server response", getClass().getName() + ": ERRO:" + status); + scheduleJob(context, notificationReturn); + break; + } + + } + + @Override + public void onFailure(Call<NotificationReturn> call, Throwable t) { + Log.e("Server response", getClass().getName() + ": Requisição falhou!!"); + t.printStackTrace(); + } + }); + + } + + 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(); + + } + + + private void scheduleJob(Context context, NotificationReturn notificationReturn){ + + FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher( + new GooglePlayDriver(context) + ); + + Bundle extras = new Bundle(); + + extras.putString(Utils.NOTIFICATION, new Gson().toJson(notificationReturn)); + + Job job = dispatcher.newJobBuilder() + .setService(NotificationReadService.class) + .setTag(Utils.NOTIFICATION_READ_SERVICE) + //time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600 + //will be repeated every 10 minutes + .setTrigger(Trigger.NOW) + //will be retried if it fails. + .setRetryStrategy(RetryStrategy.DEFAULT_LINEAR) + .setExtras(extras) + .setConstraints( + // only run on network + Constraint.ON_ANY_NETWORK + ) + //if device is rebooted the job will be restarted + .setLifetime(Lifetime.FOREVER) + .build(); + dispatcher.mustSchedule(job); + } } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java index 144bf8d..4898109 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java @@ -1,11 +1,8 @@ package br.ufpr.c3sl.agendador.agendador.services.notification; import android.content.Context; -import android.os.Looper; import android.util.Log; import android.util.LongSparseArray; -import android.util.SparseArray; -import android.util.SparseLongArray; import com.firebase.jobdispatcher.JobParameters; import com.firebase.jobdispatcher.JobService; @@ -43,13 +40,12 @@ public class NotificationsListService extends JobService { @Override public boolean onStartJob(final JobParameters job) { - Log.d("AGNDDR-NotifiUpdate", "Estou no Job"); new Thread(new Runnable() { public void run() { - Log.v("AGNDDR-NotifiUpdate", "Rodando " + NotificationsListService.class.getName()); + Log.v("Notificacao", "Rodando " + NotificationsListService.class.getName()); Map<String, String> header = new HashMap<>(); ObscuredSharedPreferences osb = ObscuredSharedPreferences.getPrefs(getBaseContext(), "Agendador", Context.MODE_PRIVATE); header.put("Content-Type", "application/json"); @@ -68,11 +64,6 @@ public class NotificationsListService extends JobService { private void requestNotificationUpdate(final Map<String, String> header, final JobParameters job, final ObscuredSharedPreferences osb){ final ApiEndpoints service = ApiUtils.request(header); - Log.v("AGNDDR-NotifiUpdate", Utils.ACCESS_TOKEN + osb.getString(Utils.ACCESS_TOKEN, "NADA")); - Log.v("AGNDDR-NotifiUpdate", Utils.CLIENT + osb.getString(Utils.CLIENT, "NADA")); - Log.v("AGNDDR-NotifiUpdate", Utils.UID + osb.getString(Utils.UID, "NADA")); - - Call<List<NotificationReturn>> listCall = service.requestNotifications(); @@ -87,30 +78,28 @@ public class NotificationsListService extends JobService { switch (status) { case 200: case 201: - Log.d("Server response", getClass().getName() + ": 200 - Sucesso!"); new Thread(new Runnable() { public void run() { Gson gson = new Gson(); - LongSparseArray<Notification> localNotifications = new LongSparseArray<>(); - List<Notification> list = LocalNotificationManager.getList(osb, gson); - for(Notification n : list) - localNotifications.append(n.scheduleId, n); + LongSparseArray<NotificationReturn> newLocalNotifications = new LongSparseArray<>(); + List<NotificationReturn> list = LocalNotificationManager.getList(osb, gson); + for(NotificationReturn n : list){ + newLocalNotifications.append(n.notificationId, n); + } for(NotificationReturn nr : responseList){ - if(localNotifications.get(nr.scheduleId) == null){ + if(newLocalNotifications.get(nr.notificationId) == null && nr.hasRead == 0){ LocalNotificationManager.createLocalNotification(getApplicationContext(), - new Notification(nr.scheduleId, nr.reminderTime, nr.hasRead == 0, - nr.description, nr.emailAddres, nr.emailSent == 0), - osb, gson); + nr, osb, gson); } } + jobFinished(job, false); }}).start(); break; default: Log.e("Server response", getClass().getName() + ": ERRO:" + status); - jobFinished(job, false); break; } @@ -120,7 +109,6 @@ public class NotificationsListService extends JobService { @Override public void onFailure(Call<List<NotificationReturn>> call, Throwable t) { Log.e("Server response", getClass().getName() + ": Requisição falhou!!"); - t.printStackTrace(); jobFinished(job, false); } }); -- GitLab From ceae49b9a3e85dfd4cdbe65496c940051b130f50 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Thu, 25 Jan 2018 10:54:21 -0200 Subject: [PATCH 7/9] AGILE#307: Adjusted recurring time of background service. Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- .../agendador/agendador/models/NotificationReturn.java | 8 +++++--- .../c3sl/agendador/agendador/network/ApiEndpoints.java | 2 +- .../agendador/agendador/presenters/LoginPresenter.java | 2 +- .../agendador/presenters/SchedulingPresenter.java | 1 + .../services/notification/NotificationsListService.java | 8 ++++++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java index 7887795..c752e4b 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/NotificationReturn.java @@ -27,7 +27,7 @@ public class NotificationReturn implements Parcelable{ public String reminderTime; @SerializedName("read") - public int hasRead; + public boolean hasRead; @SerializedName("content") public String description; @@ -35,6 +35,8 @@ public class NotificationReturn implements Parcelable{ @SerializedName("reminder_email") public String emailAddress; + + //todo: Mudar para boolean quando o back-end atualizar @SerializedName("reminder_email_sent") public int emailSent; @@ -53,7 +55,7 @@ public class NotificationReturn implements Parcelable{ scheduleId = pc.readLong(); resourceScheduleId = pc.readLong(); reminderTime = pc.readString(); - hasRead = pc.readInt(); + hasRead = pc.readByte() != 0; description = pc.readString(); emailAddress = pc.readString(); emailSent = pc.readInt(); @@ -84,7 +86,7 @@ public class NotificationReturn implements Parcelable{ dest.writeLong(scheduleId == null ? 0 : scheduleId); dest.writeLong(resourceScheduleId == null ? 0 : resourceScheduleId); dest.writeString(reminderTime == null ? "" : reminderTime); - dest.writeInt(hasRead); + dest.writeByte((byte) (hasRead ? 1 : 0)); dest.writeString(description == null ? "" : description); dest.writeString(emailAddress == null ? "" : emailAddress); dest.writeInt(emailSent); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java index 6d351fc..99c152a 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java @@ -95,7 +95,7 @@ public interface ApiEndpoints { @GET("forms/schedule_history?permission=citizen") Call<FormFilters> requestCitizenSectors(); - @POST("notifications?permission=2") + @POST("notifications?permission=citizen") Call<NotificationReturn> requestCreateNotification(@Body Notification notification); @GET("schedules/{id_schedule}?permission=citizen") diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java index 6416763..e084fd3 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java @@ -172,7 +172,7 @@ public class LoginPresenter extends BasePresenter<LoginView> { .setService(ImageUpdateService.class) .setTag(Utils.SERVICE_UPDATE_IMAGE) //time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600 - .setTrigger(Trigger.executionWindow(60, 3600)) + .setTrigger(Trigger.executionWindow(580, 610)) //will be retried if it fails. .setRecurring(true) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulingPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulingPresenter.java index 580504a..42b3455 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulingPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulingPresenter.java @@ -93,6 +93,7 @@ public class SchedulingPresenter extends BasePresenter<SchedulingView> { header.put(Utils.CLIENT, osb.getString(Utils.CLIENT, null)); header.put(Utils.UID, osb.getString(Utils.UID, null)); + final ApiEndpoints service = ApiUtils.request(header); Call<ScheduleConfirmation> listCall = service.requestConfirmSchedule(schedule.getmId(), citizen.getId()); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java index 4898109..8300288 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationsListService.java @@ -83,12 +83,15 @@ public class NotificationsListService extends JobService { Gson gson = new Gson(); LongSparseArray<NotificationReturn> newLocalNotifications = new LongSparseArray<>(); List<NotificationReturn> list = LocalNotificationManager.getList(osb, gson); + Log.d("Notificacao", "NOTIFICACOES LOCAIS!!!!!!!!!"); for(NotificationReturn n : list){ newLocalNotifications.append(n.notificationId, n); + Log.d("Notificacao", gson.toJson(n)); } - + Log.d("Notificacao", "NOTIFICACOES NO SERVIDOR"); for(NotificationReturn nr : responseList){ - if(newLocalNotifications.get(nr.notificationId) == null && nr.hasRead == 0){ + Log.d("Notificacao", gson.toJson(nr)); + if(newLocalNotifications.get(nr.notificationId) == null && nr.hasRead){ LocalNotificationManager.createLocalNotification(getApplicationContext(), nr, osb, gson); } @@ -100,6 +103,7 @@ public class NotificationsListService extends JobService { break; default: Log.e("Server response", getClass().getName() + ": ERRO:" + status); + jobFinished(job, false); break; } -- GitLab From 65b47b50e72dc7f3a2b17573981e606794fb7f69 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Thu, 25 Jan 2018 11:20:40 -0200 Subject: [PATCH 8/9] AGILE#307: Adjusted recurring time of background service (NotificationListService). Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- .../agendador/agendador/LoginActivity.java | 23 +------------- .../agendador/presenters/LoginPresenter.java | 31 ++++++++++++++++++- .../ScheduleConfirmationPresenter.java | 1 - 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java index ebe2a46..aa5b99e 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/LoginActivity.java @@ -215,29 +215,8 @@ public class LoginActivity extends AppCompatActivity implements LoginView { @Override public void afterSuccessfulLogin() { - FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher( - new GooglePlayDriver(this) - ); - - Job job = dispatcher.newJobBuilder() - .setService(NotificationsListService.class) - .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)) - //will be retried if it fails. - .setRecurring(true) - .setRetryStrategy(RetryStrategy.DEFAULT_LINEAR) - .setConstraints( - // only run on network - Constraint.ON_ANY_NETWORK - ) - //if device is rebooted the job will be restarted - .setLifetime(Lifetime.FOREVER) - .build(); - dispatcher.mustSchedule(job); - Log.d("AGNDDR-NotifiUpdate", "Job agendado para atualizar lista de coisas"); + presenter.createServiceLocalNotificationsList(); Intent intent = new Intent(LoginActivity.this, HomeActivity.class); startActivity(intent); finish(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java index e084fd3..14de8ae 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/LoginPresenter.java @@ -35,6 +35,7 @@ import br.ufpr.c3sl.agendador.agendador.models.AccountOutput; import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints; import br.ufpr.c3sl.agendador.agendador.network.ApiUtils; import br.ufpr.c3sl.agendador.agendador.services.ImageUpdateService; +import br.ufpr.c3sl.agendador.agendador.services.notification.NotificationsListService; import br.ufpr.c3sl.agendador.agendador.views.LoginView; import okhttp3.Headers; import okhttp3.ResponseBody; @@ -172,7 +173,7 @@ public class LoginPresenter extends BasePresenter<LoginView> { .setService(ImageUpdateService.class) .setTag(Utils.SERVICE_UPDATE_IMAGE) //time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600 - .setTrigger(Trigger.executionWindow(580, 610)) + .setTrigger(Trigger.executionWindow(60, 3600)) //will be retried if it fails. .setRecurring(true) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) @@ -194,6 +195,34 @@ public class LoginPresenter extends BasePresenter<LoginView> { } + + + public void createServiceLocalNotificationsList(){ + + FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher( + new GooglePlayDriver(context) + ); + + Job job = dispatcher.newJobBuilder() + .setService(NotificationsListService.class) + .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(570, 610)) + //will be retried if it fails. + .setRecurring(true) + .setRetryStrategy(RetryStrategy.DEFAULT_LINEAR) + .setConstraints( + // only run on network + Constraint.ON_ANY_NETWORK + ) + //if device is rebooted the job will be restarted + .setLifetime(Lifetime.FOREVER) + .build(); + + dispatcher.mustSchedule(job); + } + // TODO: 03/05/17 Adapt function to scenario with different file extensions, if needed. private void checkLocalPhoto(){ diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java index 88e032b..b9d512a 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java @@ -161,7 +161,6 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm Job job = dispatcher.newJobBuilder() .setService(NotificationCreateService.class) .setTag(Utils.NOTIFICATION_SERVICE + notification.scheduleId) - //time the function gets is in seconds, 60s = 1 minutes, 1 hour = 3600 .setTrigger(Trigger.NOW) //will be retried if it fails. .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) -- GitLab From da5258bb2cb64fdddadd41a5032442519546d2f0 Mon Sep 17 00:00:00 2001 From: "Lucas B. Cunha" <lbc16@inf.ufpr.br> Date: Thu, 25 Jan 2018 11:46:45 -0200 Subject: [PATCH 9/9] AGILE#316: Notification is now created at the same time that schedule is confirmed Signed-off-by: Lucas B. Cunha <lbc16@inf.ufpr.br> --- app/src/main/AndroidManifest.xml | 9 -- .../ScheduleConfirmationActivity.java | 60 ++++----- .../agendador/models/ScheduleNote.java | 4 +- .../agendador/network/ApiEndpoints.java | 5 +- .../ScheduleConfirmationPresenter.java | 89 +------------ .../presenters/SchedulesPresenter.java | 2 +- .../NotificationCreateService.java | 122 ------------------ .../views/ScheduleConfirmationView.java | 4 - 8 files changed, 39 insertions(+), 256 deletions(-) delete mode 100644 app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ac0f7c6..41368bc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,15 +58,6 @@ </intent-filter> </service> - <service - android:name=".services.notification.NotificationCreateService" - 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.NotificationsListService" android:exported="false" diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java index a07cf0a..8907f25 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/ScheduleConfirmationActivity.java @@ -217,7 +217,33 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S } if(schedule){ - scheduleConfirmationPresenter.onScheduleClicked(scheduleConfirmation, citizen, et_scheduleNote.getText().toString()); + + SimpleDateFormat sdfServer = new SimpleDateFormat(Utils.SERVER_FORMAT, Locale.getDefault()); + SimpleDateFormat sdfDate = new SimpleDateFormat(Utils.DATE_FORMAT, Locale.getDefault()); + SimpleDateFormat sdfHour = new SimpleDateFormat(Utils.HOUR_FORMAT, Locale.getDefault()); + + + /* + * Position zero is "don't notify" + */ + Notification notification = null; + if(sp_notification.getSelectedItemPosition() != reminderTimeArray.length - 1) { + notification = new Notification(); + notification.scheduleId = scheduleConfirmation.getId(); + notification.emailSent = false; + + notification.description = getResources().getString(R.string.notification_content, sdfDate.format(scheduleConfirmation.getStartTime()), sdfHour.format(scheduleConfirmation.getStartTime()), scheduleConfirmation.getServiceTypeName(), + scheduleConfirmation.getLocationName(), scheduleConfirmation.getAddressStreet(), scheduleConfirmation.getAddressNumber()); + + + notification.reminderTime = sdfServer.format(scheduleConfirmation.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()])); + + if (rb_yes.isChecked()) { + notification.emailAddress = et_email.getText().toString(); + } + } + + scheduleConfirmationPresenter.onScheduleClicked(scheduleConfirmation, citizen, et_scheduleNote.getText().toString(), notification); bt_schedule.setEnabled(false); bt_back.setEnabled(false); } @@ -366,40 +392,8 @@ public class ScheduleConfirmationActivity extends AppCompatActivity implements S } } - @Override - public void onSuccess(ScheduleConfirmation schedule){ - - SimpleDateFormat sdfServer = new SimpleDateFormat(Utils.SERVER_FORMAT, Locale.getDefault()); - SimpleDateFormat sdfDate = new SimpleDateFormat(Utils.DATE_FORMAT, Locale.getDefault()); - SimpleDateFormat sdfHour = new SimpleDateFormat(Utils.HOUR_FORMAT, Locale.getDefault()); - /* - * Position zero is "don't notify" - */ - - if(sp_notification.getSelectedItemPosition() != reminderTimeArray.length - 1){ - Notification notification = new Notification(); - notification.scheduleId = schedule.getId(); - notification.emailSent = false; - - notification.description = getResources().getString(R.string.notification_content, sdfDate.format(schedule.getStartTime()), sdfHour.format(schedule.getStartTime()), schedule.getServiceTypeName(), - schedule.getLocationName(), schedule.getAddressStreet(), schedule.getAddressNumber()); - - // TODO: 15/01/18 Apagar aqui o tempo a mais que está sendo usado no calculo da notificaçõa, está em dobro. - notification.reminderTime = sdfServer.format(schedule.getStartTime().getTime() - (reminderTimeArray[sp_notification.getSelectedItemPosition()]) - (reminderTimeArray[sp_notification.getSelectedItemPosition()])); - - if(rb_yes.isChecked()){ - notification.emailAddress = et_email.getText().toString(); - } - - scheduleConfirmationPresenter.createNotification(notification); - }else{ - returnHome(); - } - - } - private void radioButtonNotificationSelected(int id, boolean toggle){ switch (id){ diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java index 8397ca4..05b6769 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/models/ScheduleNote.java @@ -3,13 +3,15 @@ package br.ufpr.c3sl.agendador.agendador.models; import com.google.gson.annotations.SerializedName; /** - * Created by lbc16 on 19/09/17. + * Created by Lucas Braz Cunha on 19/09/17. */ public class ScheduleNote { public Schedule schedule; + public Notification notification; + public ScheduleNote(String note) { this.schedule = new Schedule(note); } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java index 99c152a..268289f 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/network/ApiEndpoints.java @@ -89,9 +89,12 @@ public interface ApiEndpoints { @PUT("citizens/{id_user}/dependants/{id_dependent}?permission=citizen") Call<FullDependent> updateDependent(@Path("id_user") long citizenId, @Path("id_dependent") long dependentId, @Body DependentCreation dependent); - @GET("schedules?permission=citizen") + @GET("schedules?permission=citizen&history=true") Call<CheckSchedules> requestSchedulesHistory(@QueryMap Map<String, String> options); + @GET("schedules?permission=citizen&future=true") + Call<CheckSchedules> requestFutureSchedules(@QueryMap Map<String, String> options); + @GET("forms/schedule_history?permission=citizen") Call<FormFilters> requestCitizenSectors(); diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java index b9d512a..0a96900 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/ScheduleConfirmationPresenter.java @@ -1,17 +1,10 @@ package br.ufpr.c3sl.agendador.agendador.presenters; import android.content.Context; -import android.os.Bundle; import android.util.Log; -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.Map; @@ -21,13 +14,10 @@ import br.ufpr.c3sl.agendador.agendador.helpers.ObscuredSharedPreferences; import br.ufpr.c3sl.agendador.agendador.helpers.Utils; import br.ufpr.c3sl.agendador.agendador.models.CitizenCompact; import br.ufpr.c3sl.agendador.agendador.models.Notification; -import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn; import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; import br.ufpr.c3sl.agendador.agendador.models.ScheduleNote; import br.ufpr.c3sl.agendador.agendador.network.ApiEndpoints; import br.ufpr.c3sl.agendador.agendador.network.ApiUtils; -import br.ufpr.c3sl.agendador.agendador.services.notification.LocalNotificationManager; -import br.ufpr.c3sl.agendador.agendador.services.notification.NotificationCreateService; import okhttp3.Headers; import retrofit2.Call; import retrofit2.Callback; @@ -54,7 +44,7 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm } - public void onScheduleClicked(final ScheduleConfirmation scheduleConfirmation, CitizenCompact citizen, String note){ + public void onScheduleClicked(final ScheduleConfirmation scheduleConfirmation, CitizenCompact citizen, String note, Notification notification){ Map<String, String> header = new HashMap<>(); header.put("Content-Type", "application/json"); header.put(Utils.ACCESS_TOKEN, osb.getString(Utils.ACCESS_TOKEN, null)); @@ -65,6 +55,8 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm ScheduleNote scheduleNote = new ScheduleNote(note); + scheduleNote.notification = notification; + Call<ScheduleConfirmation> listCall = service.requestPerformScheduling(scheduleConfirmation.getId(), citizen.getId(), scheduleNote); scheduleConfirmationPresenter.view().setProgressBar(true); @@ -80,7 +72,7 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm case 200: Log.d("Server response", this.getClass().getName() + ": 200 - Sucesso!"); scheduleConfirmationPresenter.view().setProgressBar(false); - scheduleConfirmationPresenter.view().onSuccess(scheduleConfirmation); + scheduleConfirmationPresenter.view().returnHome(); break; default: @@ -102,79 +94,6 @@ public class ScheduleConfirmationPresenter extends BasePresenter<ScheduleConfirm } - public void createNotification(final Notification notification){ - Map<String, String> header = new HashMap<>(); - 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)); - - - final ApiEndpoints service = ApiUtils.request(header); - - final Call<NotificationReturn> listCall = service.requestCreateNotification(notification); - scheduleConfirmationPresenter.view().setProgressBar(true); - 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); - switch (status) { - case 201: - Log.d("Server response", this.getClass().getName() + ": 200 - Sucess!"); - scheduleConfirmationPresenter.view().setProgressBar(false); - scheduleConfirmationPresenter.view().returnHome(); - 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."); - scheduleNotificationJob(notification); - scheduleConfirmationPresenter.view().setProgressBar(false); - scheduleConfirmationPresenter.view().returnHome(); - break; - } - } - @Override - public void onFailure(Call<NotificationReturn> call, Throwable t) { - Log.e("Server response", this.getClass().getName() + ": Request Failed, Scheduling job."); - t.printStackTrace(); - scheduleNotificationJob(notification); - scheduleConfirmationPresenter.view().setProgressBar(false); - scheduleConfirmationPresenter.view().returnHome(); - } - }); - - } - - - - private void scheduleNotificationJob(Notification notification){ - Bundle extras = new Bundle(); - - Gson g = new Gson(); - String json = g.toJson(notification); - - extras.putString(Utils.NOTIFICATION, json); - - Job job = dispatcher.newJobBuilder() - .setService(NotificationCreateService.class) - .setTag(Utils.NOTIFICATION_SERVICE + notification.scheduleId) - .setTrigger(Trigger.NOW) - //will be retried if it fails. - .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) - .setConstraints( - // only run on network - Constraint.ON_ANY_NETWORK - ) - .setExtras(extras) - //if device is rebooted the job will be restarted - .setLifetime(Lifetime.FOREVER) - .build(); - dispatcher.mustSchedule(job); - } - @Override protected void updateView() {} } diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java index bfdd7a0..d17c668 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/presenters/SchedulesPresenter.java @@ -51,7 +51,7 @@ public class SchedulesPresenter extends BasePresenter<SchedulesActivity> { // TODO: 06/10/17 Change to request "active" schedules1 - Call<CheckSchedules> listCall = service.requestSchedulesHistory(new HashMap<String, String>()); + Call<CheckSchedules> listCall = service.requestFutureSchedules(new HashMap<String, String>()); listCall.enqueue(new Callback<CheckSchedules>() { diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java deleted file mode 100644 index 0620e9f..0000000 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/services/notification/NotificationCreateService.java +++ /dev/null @@ -1,122 +0,0 @@ -package br.ufpr.c3sl.agendador.agendador.services.notification; - -import android.content.Context; -import android.os.Bundle; -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.List; -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.Notification; -import br.ufpr.c3sl.agendador.agendador.models.NotificationReturn; -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 24/11/17. - */ - -public class NotificationCreateService extends JobService { - - - @Override - public boolean onStartJob(final JobParameters job) { - Log.v("Notificacao", "Rodando " + NotificationCreateService.class.getName()); - - new Thread(new Runnable() { - public void run() { - - final Bundle extras = job.getExtras(); - 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)); - - Notification notification = null; - - if (extras != null) { - notification = new Gson().fromJson(extras.getString(Utils.NOTIFICATION), Notification.class); - } else { - Log.e("Notificacao", "Job não recebeu os extras."); - jobFinished(job, true); - } - - requestCreateNotification(header, job, osb, notification); - - - }}).start(); - - return true; - } - - - private void requestCreateNotification(final Map<String, String> header, final JobParameters job, final ObscuredSharedPreferences osb, final Notification notification){ - - final ApiEndpoints service = ApiUtils.request(header); - - Call<NotificationReturn> listCall = service.requestCreateNotification(notification); - - 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.createLocalNotification(getApplicationContext(), response.body(), 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(); - - } - - - - @Override - public boolean onStopJob(JobParameters job) { - return true; - } -} diff --git a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java index 25d0935..0c41bba 100644 --- a/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java +++ b/app/src/main/java/br/ufpr/c3sl/agendador/agendador/views/ScheduleConfirmationView.java @@ -1,7 +1,5 @@ package br.ufpr.c3sl.agendador.agendador.views; -import br.ufpr.c3sl.agendador.agendador.models.ScheduleConfirmation; - /** * Created by Lucas B. Cunha on 25/07/17. */ @@ -12,8 +10,6 @@ public interface ScheduleConfirmationView { void setProgressBar(boolean enabled); - void onSuccess(ScheduleConfirmation confirmationResponse); - void setConnectionError(boolean enabled); void returnHome(); -- GitLab