12
12
import static com .noah .timely .timetable .DaysFragment .ARG_POSITION ;
13
13
14
14
import android .app .AlarmManager ;
15
+ import android .app .NotificationManager ;
15
16
import android .app .PendingIntent ;
16
17
import android .app .Service ;
18
+ import android .content .ContentResolver ;
17
19
import android .content .Context ;
18
20
import android .content .Intent ;
21
+ import android .graphics .Bitmap ;
22
+ import android .graphics .BitmapFactory ;
23
+ import android .media .RingtoneManager ;
19
24
import android .net .Uri ;
20
25
import android .os .Build ;
21
26
import android .os .IBinder ;
22
27
23
28
import androidx .annotation .NonNull ;
24
29
import androidx .annotation .Nullable ;
30
+ import androidx .core .app .NotificationCompat ;
31
+ import androidx .core .content .ContextCompat ;
32
+ import androidx .preference .PreferenceManager ;
25
33
26
34
import com .noah .timely .R ;
27
35
import com .noah .timely .assignment .AssignmentModel ;
28
36
import com .noah .timely .assignment .Reminder ;
29
37
import com .noah .timely .assignment .SubmissionNotifier ;
30
38
import com .noah .timely .core .DataModel ;
31
39
import com .noah .timely .core .SchoolDatabase ;
40
+ import com .noah .timely .main .App ;
32
41
import com .noah .timely .scheduled .AddScheduledDialog ;
33
42
import com .noah .timely .scheduled .ScheduledTaskNotifier ;
34
43
import com .noah .timely .timetable .DaysFragment ;
35
44
import com .noah .timely .timetable .TimetableModel ;
36
45
import com .noah .timely .timetable .TimetableNotifier ;
46
+ import com .noah .timely .util .Constants ;
37
47
import com .noah .timely .util .ThreadUtils ;
38
48
39
49
import java .util .Calendar ;
45
55
* Service that would re-schedule all TimeLY alarms
46
56
*/
47
57
public class AlarmReSchedulerService extends Service {
58
+ private static final int NOTIFICATION_ID = 234543 ; // a very random number that came out of nowhere
48
59
49
60
@ Override
50
61
public int onStartCommand (Intent intent , int flags , int startId ) {
62
+ Context context = getApplicationContext ();
63
+ if (intent .getAction ().equals (Constants .ACTION .SHOW_NOTIFICATION )) {
64
+ showActivityNofication (context );
65
+ }
66
+
51
67
// make re-scheduler return immediately to avoid blocking main thread
52
68
ThreadUtils .runBackgroundTask (() -> {
53
-
54
- Context context = getApplicationContext ();
55
69
SchoolDatabase database = new SchoolDatabase (context );
56
-
57
70
// Reset the alarm here.
58
71
List <DataModel > activeAlarms = database .getActiveAlarms ();
59
72
if (!activeAlarms .isEmpty ()) {
@@ -89,6 +102,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
89
102
List <DataModel > timetables1 = database .getTimeTableData (SchoolDatabase .SCHEDULED_TIMETABLE );
90
103
if (!timetables1 .isEmpty ()) {
91
104
// re-schedule alarms; get alarm data from app's database
105
+
92
106
for (DataModel rawData : timetables1 ) {
93
107
TimetableModel timetable = (TimetableModel ) rawData ;
94
108
registerPendingScheduledTimetables (context , timetable );
@@ -105,11 +119,49 @@ public int onStartCommand(Intent intent, int flags, int startId) {
105
119
}
106
120
}
107
121
122
+ // cancel on-going notification
123
+ cancelNotification (context );
108
124
}); // end re-schedule task
109
125
126
+
110
127
return START_STICKY ;
111
128
}
112
129
130
+ private void cancelNotification (Context context ) {
131
+ NotificationManager manager = (NotificationManager ) context .getSystemService (Context .NOTIFICATION_SERVICE );
132
+ manager .cancel (NOTIFICATION_ID );
133
+ }
134
+
135
+ private void showActivityNofication (Context context ) {
136
+ Uri SYSTEM_DEFAULT = RingtoneManager .getDefaultUri (RingtoneManager .TYPE_NOTIFICATION );
137
+ Uri APP_DEFAULT = new Uri .Builder ()
138
+ .scheme (ContentResolver .SCHEME_ANDROID_RESOURCE )
139
+ .authority (context .getPackageName ())
140
+ .path (String .valueOf (R .raw .arpeggio1 ))
141
+ .build ();
142
+
143
+ String type = PreferenceManager .getDefaultSharedPreferences (context )
144
+ .getString ("Uri Type" , "TimeLY's Default" );
145
+
146
+ final Uri DEFAULT_URI = type .equals ("TimeLY's Default" ) || SYSTEM_DEFAULT == null ? APP_DEFAULT
147
+ : SYSTEM_DEFAULT ;
148
+
149
+ Bitmap icon = BitmapFactory .decodeResource (context .getResources (), R .mipmap .app_icon );
150
+ NotificationManager manager = (NotificationManager ) context .getSystemService (Context .NOTIFICATION_SERVICE );
151
+ NotificationCompat .Builder builder = new NotificationCompat .Builder (context , App .GENERAL_CHANNEL_ID );
152
+
153
+ builder .setContentTitle (getString (R .string .app_name ) + " is in the background" )
154
+ .setContentText (getString (R .string .app_name ) + " is scheduling new notifications" )
155
+ .setChannelId (App .GENERAL_CHANNEL_ID )
156
+ .setSound (DEFAULT_URI )
157
+ .setSmallIcon (R .drawable .ic_baseline_info_24 )
158
+ .setColor (ContextCompat .getColor (context , R .color .colorPrimary ))
159
+ .setLargeIcon (icon )
160
+ .setOngoing (true );
161
+
162
+ manager .notify (NOTIFICATION_ID , builder .build ());
163
+ }
164
+
113
165
@ Nullable
114
166
@ Override
115
167
public IBinder onBind (Intent intent ) {
@@ -144,7 +196,7 @@ private void registerPendingScheduledTimetables(Context context, TimetableModel
144
196
.addCategory ("com.noah.timely.scheduled" )
145
197
.setAction ("com.noah.timely.scheduled.addAction" )
146
198
.setDataAndType (Uri .parse ("content://com.noah.timely.scheduled.add." + triggerTime ),
147
- "com.noah.timely.scheduled.dataType" );
199
+ "com.noah.timely.scheduled.dataType" );
148
200
149
201
PendingIntent pi = PendingIntent .getBroadcast (context , 1156 , scheduleIntent , 0 );
150
202
@@ -183,14 +235,14 @@ private void registerPendingTimetables(Context context, TimetableModel timetable
183
235
184
236
Intent timetableIntent = new Intent (context , TimetableNotifier .class );
185
237
timetableIntent .putExtra (DaysFragment .ARG_TIME , time )
186
- .putExtra (ARG_CLASS , course )
187
- .putExtra (ARG_DAY , timetable .getCalendarDay ())
188
- .putExtra (ARG_POSITION , position )
189
- .putExtra (ARG_PAGE_POSITION , position )
190
- .addCategory ("com.noah.timely.timetable" )
191
- .setAction ("com.noah.timely.timetable.addAction" )
192
- .setDataAndType (Uri .parse ("content://com.noah.timely.add." + timeInMillis ),
193
- "com.noah.timely.dataType" );
238
+ .putExtra (ARG_CLASS , course )
239
+ .putExtra (ARG_DAY , timetable .getCalendarDay ())
240
+ .putExtra (ARG_POSITION , position )
241
+ .putExtra (ARG_PAGE_POSITION , position )
242
+ .addCategory ("com.noah.timely.timetable" )
243
+ .setAction ("com.noah.timely.timetable.addAction" )
244
+ .setDataAndType (Uri .parse ("content://com.noah.timely.add." + timeInMillis ),
245
+ "com.noah.timely.dataType" );
194
246
195
247
PendingIntent pi = PendingIntent .getBroadcast (context , 555 , timetableIntent , PendingIntent .FLAG_UPDATE_CURRENT );
196
248
@@ -231,26 +283,26 @@ private void registerPendingAssignments(Context context, AssignmentModel assignm
231
283
String ln = truncateLecturerName (context , assignment .getLecturerName ());
232
284
Intent notifyIntentCurrent = new Intent (context , SubmissionNotifier .class );
233
285
notifyIntentCurrent .putExtra (LECTURER_NAME , ln )
234
- .putExtra (TITLE , assignment .getTitle ())
235
- .putExtra (POSITION , assignment .getPosition ())
236
- .addCategory (context .getPackageName () + ".category" )
237
- .setAction (context .getPackageName () + ".update" )
238
- .setDataAndType (Uri .parse ("content://" + context .getPackageName ()),
239
- assignment .toString ());
286
+ .putExtra (TITLE , assignment .getTitle ())
287
+ .putExtra (POSITION , assignment .getPosition ())
288
+ .addCategory (context .getPackageName () + ".category" )
289
+ .setAction (context .getPackageName () + ".update" )
290
+ .setDataAndType (Uri .parse ("content://" + context .getPackageName ()),
291
+ assignment .toString ());
240
292
241
293
Intent notifyIntentPrevious = new Intent (context , Reminder .class );
242
294
notifyIntentPrevious .putExtra (LECTURER_NAME , ln )
243
- .putExtra (TITLE , assignment .getTitle ())
244
- .putExtra (NEXT_ALARM , CURRENT )
245
- .addCategory (context .getPackageName () + ".category" )
246
- .setAction (context .getPackageName () + ".update" )
247
- .setDataAndType (Uri .parse ("content://" + context .getPackageName ()),
248
- assignment .toString ());
295
+ .putExtra (TITLE , assignment .getTitle ())
296
+ .putExtra (NEXT_ALARM , CURRENT )
297
+ .addCategory (context .getPackageName () + ".category" )
298
+ .setAction (context .getPackageName () + ".update" )
299
+ .setDataAndType (Uri .parse ("content://" + context .getPackageName ()),
300
+ assignment .toString ());
249
301
250
302
PendingIntent assignmentPiPrevious = PendingIntent .getBroadcast (context , 147 , notifyIntentPrevious ,
251
- PendingIntent .FLAG_UPDATE_CURRENT );
303
+ PendingIntent .FLAG_UPDATE_CURRENT );
252
304
PendingIntent assignmentPiCurrent = PendingIntent .getBroadcast (context , 141 , notifyIntentCurrent ,
253
- PendingIntent .FLAG_UPDATE_CURRENT );
305
+ PendingIntent .FLAG_UPDATE_CURRENT );
254
306
// Exact alarms not used here, so that android can perform its normal operation
255
307
// on devices
256
308
// >= 4.4 (KITKAT) to prevent unnecessary battery drain by alarms.
@@ -272,8 +324,8 @@ private void registerPendingAssignments(Context context, AssignmentModel assignm
272
324
private String truncateLecturerName (Context context , String fullName ) {
273
325
String [] nameTokens = fullName .split (" " );
274
326
275
- String [] titles = {"Barr" , "Barrister" , "Doc" , "Doctor" , "Dr" , "Engineer" , "Engr" ,
276
- "Mr" , "Mister" , "Mrs" , "Ms" , "Prof" , "Professor" };
327
+ String [] titles = { "Barr" , "Barrister" , "Doc" , "Doctor" , "Dr" , "Engineer" , "Engr" ,
328
+ "Mr" , "Mister" , "Mrs" , "Ms" , "Prof" , "Professor" };
277
329
278
330
StringBuilder nameBuilder = new StringBuilder ();
279
331
String shortenedName = "" ;
@@ -374,11 +426,11 @@ private void rescheduleNonRepeatingAlarm(@NonNull Context context, @NonNull Alar
374
426
alarmReceiverIntent .addCategory ("com.noah.timely.alarm.category" );
375
427
alarmReceiverIntent .setAction ("com.noah.timely.alarm.cancel" );
376
428
alarmReceiverIntent .setDataAndType (Uri .parse ("content://com.noah.timely/Alarms/alarm" + alarmMillis ),
377
- "com.noah.timely.alarm.dataType" );
429
+ "com.noah.timely.alarm.dataType" );
378
430
379
431
AlarmManager alarmManager = (AlarmManager ) context .getSystemService (Context .ALARM_SERVICE );
380
432
PendingIntent alarmPI = PendingIntent .getBroadcast (context , 11789 , alarmReceiverIntent ,
381
- PendingIntent .FLAG_CANCEL_CURRENT );
433
+ PendingIntent .FLAG_CANCEL_CURRENT );
382
434
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .KITKAT ) {
383
435
// alarm has to be triggered even when device is in idle or doze mode.
384
436
// This alarm is very important
@@ -422,11 +474,11 @@ private void rescheduleRepeatingPendingAlarm(@NonNull Context context, @NonNull
422
474
alarmReceiverIntent .addCategory ("com.noah.timely.alarm.category" );
423
475
alarmReceiverIntent .setAction ("com.noah.timely.alarm.cancel" );
424
476
alarmReceiverIntent .setDataAndType (Uri .parse ("content://com.noah.timely/Alarms/alarm" + alarmMillis ),
425
- "com.noah.timely.alarm.dataType" );
477
+ "com.noah.timely.alarm.dataType" );
426
478
427
479
AlarmManager alarmManager = (AlarmManager ) context .getSystemService (Context .ALARM_SERVICE );
428
480
PendingIntent alarmPI = PendingIntent .getBroadcast (context , 11789 , alarmReceiverIntent ,
429
- PendingIntent .FLAG_UPDATE_CURRENT );
481
+ PendingIntent .FLAG_UPDATE_CURRENT );
430
482
431
483
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .KITKAT ) {
432
484
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
0 commit comments