Ensure we have scheduled jobs when the system boots or when the app starts.

This commit is contained in:
Aidan Follestad 2018-11-30 12:27:07 -08:00
parent d1672a6c5e
commit eeaa68dbe2
7 changed files with 100 additions and 1 deletions

View file

@ -46,6 +46,13 @@
android:label="@string/check_service_name"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<receiver android:name=".engine.statuscheck.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>

View file

@ -11,6 +11,7 @@ import android.app.job.JobScheduler
import android.content.Context
import com.afollestad.nocknock.di.AppComponent
import com.afollestad.nocknock.di.DaggerAppComponent
import com.afollestad.nocknock.engine.statuscheck.BootReceiver
import com.afollestad.nocknock.engine.statuscheck.CheckStatusJob
import com.afollestad.nocknock.ui.AddSiteActivity
import com.afollestad.nocknock.ui.MainActivity
@ -51,6 +52,7 @@ class App : Application(), Injector {
is ViewSiteActivity -> appComponent.inject(target)
is AddSiteActivity -> appComponent.inject(target)
is CheckStatusJob -> appComponent.inject(target)
is BootReceiver -> appComponent.inject(target)
else -> throw IllegalStateException("Can't inject into $target")
}
}

View file

@ -9,6 +9,7 @@ import android.app.Application
import android.app.NotificationManager
import android.app.job.JobScheduler
import com.afollestad.nocknock.engine.EngineModule
import com.afollestad.nocknock.engine.statuscheck.BootReceiver
import com.afollestad.nocknock.engine.statuscheck.CheckStatusJob
import com.afollestad.nocknock.notifications.NotificationsModule
import com.afollestad.nocknock.ui.AddSiteActivity
@ -40,6 +41,8 @@ interface AppComponent {
fun inject(job: CheckStatusJob)
fun inject(bootReceiver: BootReceiver)
@Component.Builder
interface Builder {

View file

@ -112,7 +112,17 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
list.addItemDecoration(DividerItemDecoration(this, VERTICAL))
fab.setOnClickListener(this)
notificationManager.createChannels()
ensureCheckJobs()
}
private fun ensureCheckJobs() {
rootView.scopeWhileAttached(IO) {
launch(coroutineContext) {
checkStatusManager.ensureScheduledChecks()
}
}
}
override fun onResume() {

View file

@ -0,0 +1,54 @@
/*
* Licensed under Apache-2.0
*
* Designed and developed by Aidan Follestad (@afollestad)
*/
package com.afollestad.nocknock.engine.statuscheck
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_BOOT_COMPLETED
import android.util.Log
import com.afollestad.nocknock.engine.BuildConfig
import com.afollestad.nocknock.utilities.ext.injector
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import javax.inject.Inject
/** @author Aidan Follestad (afollestad) */
class BootReceiver : BroadcastReceiver() {
companion object {
private fun log(message: String) {
if (BuildConfig.DEBUG) {
Log.d("BootReceiver", message)
}
}
}
@Inject lateinit var checkStatusManager: CheckStatusManager
override fun onReceive(
context: Context,
intent: Intent
) {
require(ACTION_BOOT_COMPLETED == intent.action) {
"BootReceiver should only receive ACTION_BOOT_COMPLETED intents."
}
log("Received boot event! Let's go.")
context.injector()
.injectInto(this)
val pendingResult = goAsync()
GlobalScope.launch(Main) {
async(IO) { checkStatusManager.ensureScheduledChecks() }.await()
pendingResult.resultCode = 0
pendingResult.finish()
}
}
}

View file

@ -15,6 +15,7 @@ import com.afollestad.nocknock.data.ServerModel
import com.afollestad.nocknock.data.ServerStatus.ERROR
import com.afollestad.nocknock.data.ServerStatus.OK
import com.afollestad.nocknock.engine.R
import com.afollestad.nocknock.engine.db.ServerModelStore
import com.afollestad.nocknock.engine.statuscheck.CheckStatusJob.Companion.KEY_SITE_ID
import com.afollestad.nocknock.utilities.BuildConfig
import com.afollestad.nocknock.utilities.providers.StringProvider
@ -33,6 +34,8 @@ data class CheckResult(
/** @author Aidan Follestad (afollestad) */
interface CheckStatusManager {
suspend fun ensureScheduledChecks()
fun scheduleCheck(
site: ServerModel,
rightNow: Boolean = false
@ -47,7 +50,8 @@ class RealCheckStatusManager @Inject constructor(
private val app: Application,
private val jobScheduler: JobScheduler,
private val okHttpClient: OkHttpClient,
private val stringProvider: StringProvider
private val stringProvider: StringProvider,
private val siteStore: ServerModelStore
) : CheckStatusManager {
companion object {
@ -59,6 +63,25 @@ class RealCheckStatusManager @Inject constructor(
}
}
override suspend fun ensureScheduledChecks() {
val sites = siteStore.get()
if (sites.isEmpty()) {
return
}
log("Ensuring sites have scheduled checks.")
sites.forEach { site ->
val existingJob = jobScheduler.allPendingJobs
.firstOrNull { job -> job.id == site.id }
if (existingJob == null) {
log("Site ${site.id} does NOT have a scheduled job, running one now.")
scheduleCheck(site, rightNow = true)
} else {
log("Site ${site.id} already has a scheduled job. Nothing to do.")
}
}
}
override fun scheduleCheck(
site: ServerModel,
rightNow: Boolean