Notifications now use AlarmManager instead of WorkManager for delivery, TODO: notifications should be sent even if the app is closed (swiped from 'recents' view)

This commit is contained in:
Deniz Düzgören
2020-03-10 19:42:30 +01:00
parent 80f737a96c
commit ea393603c0
37 changed files with 411 additions and 50 deletions
-2
View File
@@ -54,8 +54,6 @@ dependencies {
implementation "androidx.room:room-runtime:2.2.3"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.work:work-runtime-ktx:2.3.3"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
Binary file not shown.
+2 -2
View File
@@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"properties": [],
"versionCode": 1,
"versionName": "1",
"versionCode": 2,
"versionName": "2",
"enabled": true,
"outputFile": "app-release.apk"
}
+3
View File
@@ -12,6 +12,9 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.Launcher">
<service android:name=".util.ExamService"
android:description="@string/exam_service_description"
android:enabled="true"/>
<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -1,22 +1,26 @@
package com.denizd.qwark.activity
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.work.*
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.database.QwarkRepository
import com.denizd.qwark.databinding.ActivityMainBinding
import com.denizd.qwark.fragment.*
import com.denizd.qwark.util.Dependencies
import com.denizd.qwark.util.ExamNotificationWorker
import com.denizd.qwark.util.ExamService
import com.denizd.qwark.util.QwarkUtil
import com.denizd.qwark.viewmodel.MainViewModel
import java.util.concurrent.TimeUnit
import kotlin.random.Random
class MainActivity : FragmentActivity() {
@@ -88,16 +92,23 @@ class MainActivity : FragmentActivity() {
// }, 1200)
Dependencies.repo.allCoursesWithExams.observe(this, Observer { courses ->
with (WorkManager.getInstance(this)) {
with (getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
for (course in courses) {
beginUniqueWork(
"${course.name}-${course.courseId}",
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequestBuilder<ExamNotificationWorker>()
.setInitialDelay(getTimeUntil(course.examTime), TimeUnit.MILLISECONDS)
.setInputData(Data.Builder().putString("course", course.name).build())
.build()
).enqueue()
// val t = getTimeUntil(course.examTime)
if (course.examTime > QwarkUtil.timeAtMidnight || !(QwarkUtil.timeAtMidnight + viewModel.getExamNotificationTime()).hasPassed()) {
set(
AlarmManager.RTC,
course.examTime + viewModel.getExamNotificationTime(),
PendingIntent.getService(
this@MainActivity,
course.courseId,
Intent(this@MainActivity, ExamService::class.java).also { intent ->
intent.putExtra("course", course.name)
},
PendingIntent.FLAG_UPDATE_CURRENT
)
)
}
}
}
})
@@ -154,6 +165,6 @@ class MainActivity : FragmentActivity() {
}
}
// TODO add option to set time of notification (currently: 7 AM)
private fun getTimeUntil(examTime: Long): Long = examTime + viewModel.getExamNotificationTime() - System.currentTimeMillis()
private fun Long.hasPassed(): Boolean = this < System.currentTimeMillis()
}
@@ -20,8 +20,8 @@ interface QwarkDao {
@Query("SELECT course.*, (SELECT MIN(exam_time) FROM grade WHERE grade.course_id = course.course_id AND exam_time >= :time) AS exam_time FROM course GROUP BY course.course_id ORDER BY time")
fun getAllCourseExams(time: Long = QwarkUtil.timeAtMidnight): List<CourseExam>
@Query("SELECT course.*, (SELECT MIN(exam_time) FROM grade WHERE grade.course_id = course.course_id AND exam_time >= :time) AS exam_time FROM course WHERE exam_time > :time GROUP BY course.course_id ORDER BY time")
fun getAllCoursesWithExams(time: Long = QwarkUtil.timeAtMidnight + 25200000L): LiveData<List<CourseExam>>
@Query("SELECT course.*, (SELECT MIN(exam_time) FROM grade WHERE grade.course_id = course.course_id AND exam_time >= :timeAtMidnight) AS exam_time FROM course WHERE exam_time > -1 GROUP BY course.course_id ORDER BY time")
fun getAllCoursesWithExams(timeAtMidnight: Long = QwarkUtil.timeAtMidnight): LiveData<List<CourseExam>>
@Query("SELECT *, -1 AS exam_time FROM course WHERE course_id != :u ORDER BY time")
fun getAllCourses(u: Int = -1): List<CourseExam> // the u variable is an unnecessary workaround to return a list instead of LiveData
@@ -1,6 +1,7 @@
package com.denizd.qwark.util
import android.annotation.TargetApi
import android.app.IntentService
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
@@ -8,43 +9,40 @@ import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.denizd.qwark.R
import com.denizd.qwark.activity.MainActivity
private const val notificationChannelId = "qwark_exam_notification"
class ExamNotificationWorker(private val context: Context, workerParams: WorkerParameters) : Worker(context.applicationContext, workerParams) {
class ExamService : IntentService("ExamService") {
override fun doWork(): Result {
sendNotification(course = inputData.getString("course") ?: "error")
return Result.success()
override fun onHandleIntent(intent: Intent?) {
sendNotification(course = intent?.getStringExtra("course") ?: "error")
}
// TODO launch fragment from intent and launch the fragment for the course
private fun sendNotification(course: String) {
val openAppPending = PendingIntent.getActivity(
context, 0,
Intent(context, MainActivity::class.java).also { intent ->
this, 0,
Intent(this, MainActivity::class.java).also { intent ->
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + Intent.FLAG_ACTIVITY_CLEAR_TASK
}, 0
)
val notificationService = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationService = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(context, notificationService)
createNotificationChannel(this, notificationService)
}
val notification = NotificationCompat.Builder(context, notificationChannelId)
val notification = NotificationCompat.Builder(this, notificationChannelId)
// .setStyle(NotificationCompat.BigTextStyle())
.setContentTitle(context.getString(R.string.exam_reminder, course))
.setContentText(context.getString(R.string.writing_an_exam_today, course))
.setContentTitle(this.getString(R.string.exam_reminder, course))
.setContentText(this.getString(R.string.writing_an_exam_today, course))
.setContentIntent(openAppPending)
.setAutoCancel(true)
.setColor(context.getColor(R.color.colorAccent))
.setColor(this.getColor(R.color.colorAccent))
.setSmallIcon(R.drawable.bolt)
.build()
@@ -54,7 +52,8 @@ class ExamNotificationWorker(private val context: Context, workerParams: WorkerP
@TargetApi(26)
private fun createNotificationChannel(context: Context, notificationManager: NotificationManager) {
if (!Dependencies.repo.prefs.getIsNotificationChannelCreated()) {
notificationManager.createNotificationChannel(NotificationChannel(
notificationManager.createNotificationChannel(
NotificationChannel(
notificationChannelId, context.getString(R.string.exams), NotificationManager.IMPORTANCE_DEFAULT
).also { channel ->
channel.enableLights(true)
+1
View File
@@ -19,6 +19,7 @@
<string name="exams">Klausuren</string>
<string name="exam_reminder">Klausurerinnerung: %s</string>
<string name="writing_an_exam_today">Heute schreibst du eine Klausur in %s!</string>
<string name="exam_service_description">Verschickt Benachrichtigungen für anstehende Klausuren</string>
<!-- CourseFragment.kt -->
<string name="course">Kurs</string>
+1
View File
@@ -21,6 +21,7 @@
<string name="exams">Exams</string>
<string name="exam_reminder">Exam reminder: %s</string>
<string name="writing_an_exam_today">You\'re writing an exam in %s today!</string>
<string name="exam_service_description">Sends notifications for upcoming exams</string>
<string-array name="greetings">
<item>Hello %s!</item>