work manager

This commit is contained in:
Philipp Heckel 2021-10-28 20:41:34 -04:00
parent 573ab5db19
commit bd6d6344f5
3 changed files with 133 additions and 8 deletions

View file

@ -48,6 +48,8 @@ android {
} }
dependencies { dependencies {
def workManagerVersion = "2.5.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion" implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
implementation "androidx.core:core-ktx:$rootProject.coreKtxVersion" implementation "androidx.core:core-ktx:$rootProject.coreKtxVersion"
@ -55,6 +57,10 @@ dependencies {
implementation "androidx.activity:activity-ktx:$rootProject.activityVersion" implementation "androidx.activity:activity-ktx:$rootProject.activityVersion"
implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.code.gson:gson:2.8.8'
// WorkManager
implementation("androidx.work:work-runtime:$workManagerVersion")
implementation("androidx.work:work-runtime-ktx:$workManagerVersion")
// RecyclerView // RecyclerView
implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerViewVersion" implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerViewVersion"

View file

@ -0,0 +1,107 @@
package io.heckel.ntfy.data
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import io.heckel.ntfy.R
import kotlinx.coroutines.*
import java.net.HttpURLConnection
import java.net.URL
import kotlin.random.Random
class ConnectionWorker(val ctx: Context, workerParams: WorkerParameters) : CoroutineWorker(ctx, workerParams) {
private val gson = GsonBuilder().create()
override suspend fun doWork(): Result {
println("PHIL work started")
while (isStopped) {
openConnection(Random.nextLong(), "https://ntfy.sh/test/json")
}
println("PHIL work ended")
// Indicate whether the work finished successfully with the Result
return Result.success()
}
private fun openConnection(subscriptionId: Long, topicUrl: String) {
println("Connecting to $topicUrl ...")
val conn = (URL(topicUrl).openConnection() as HttpURLConnection).also {
it.doInput = true
it.readTimeout = READ_TIMEOUT
}
try {
println("PHIL connected")
val input = conn.inputStream.bufferedReader()
while (isStopped) {
val line = input.readLine() ?: break // Break if EOF is reached, i.e. readLine is null
val json = gson.fromJson(line, JsonObject::class.java) ?: break // Break on unexpected line
val validNotification = !json.isJsonNull
&& !json.has("event") // No keepalive or open messages
&& json.has("message")
if (validNotification) {
val title = "ntfy.sh/test"
val message = json.get("message").asString
displayNotification(title, message)
println("notification received: ${json.get("message").asString}")
}
}
} catch (e: Exception) {
println("Connection error: " + e)
} finally {
conn.disconnect()
}
println("Connection terminated: $topicUrl")
}
private fun displayNotification(title: String, message: String) {
val notificationManager =
ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId = ctx.getString(R.string.notification_channel_id)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = ctx.getString(R.string.notification_channel_name)
val descriptionText = ctx.getString(R.string.notification_channel_name)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(channelId, name, importance).apply {
description = descriptionText
}
notificationManager.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(ctx, channelId)
.setSmallIcon(R.drawable.ntfy)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
notificationManager.notify(Random.nextInt(), notification)
}
/**
* Create the NotificationChannel, but only on API 26+ because
* the NotificationChannel class is new and not in the support library
*/
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = ctx.getString(R.string.notification_channel_id)
val name = ctx.getString(R.string.notification_channel_name)
val descriptionText = ctx.getString(R.string.notification_channel_name)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(channelId, name, importance).apply {
description = descriptionText
}
// Register the channel with the system
val notificationManager: NotificationManager =
ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}

View file

@ -15,17 +15,18 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.work.*
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.*
import io.heckel.ntfy.data.Status import java.net.HttpURLConnection
import io.heckel.ntfy.data.Subscription import java.net.URL
import io.heckel.ntfy.data.topicShortUrl import java.util.concurrent.TimeUnit
import kotlin.random.Random import kotlin.random.Random
const val SUBSCRIPTION_ID = "topic_id"
class MainActivity : AppCompatActivity(), AddFragment.AddSubscriptionListener { class MainActivity : AppCompatActivity(), AddFragment.AddSubscriptionListener {
private val uniqueWorkName = "connectionWorker"
private val subscriptionsViewModel by viewModels<SubscriptionsViewModel> { private val subscriptionsViewModel by viewModels<SubscriptionsViewModel> {
SubscriptionsViewModelFactory() SubscriptionsViewModelFactory()
} }
@ -76,7 +77,8 @@ class MainActivity : AppCompatActivity(), AddFragment.AddSubscriptionListener {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.menu_action_source -> { R.id.menu_action_source -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_source_url)))) // startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_source_url))))
enqueueConnectionWorker()
true true
} }
R.id.menu_action_website -> { R.id.menu_action_website -> {
@ -101,6 +103,15 @@ class MainActivity : AppCompatActivity(), AddFragment.AddSubscriptionListener {
subscriptionsViewModel.add(subscription) subscriptionsViewModel.add(subscription)
} }
private fun enqueueConnectionWorker() {
val workRequest =
PeriodicWorkRequestBuilder<ConnectionWorker>(1, TimeUnit.MINUTES)
.build()
WorkManager
.getInstance(this)
.enqueueUniquePeriodicWork(uniqueWorkName, ExistingPeriodicWorkPolicy.KEEP, workRequest)
}
private fun displayNotification(n: Notification) { private fun displayNotification(n: Notification) {
val channelId = getString(R.string.notification_channel_id) val channelId = getString(R.string.notification_channel_id)
val notification = NotificationCompat.Builder(this, channelId) val notification = NotificationCompat.Builder(this, channelId)
@ -132,3 +143,4 @@ class MainActivity : AppCompatActivity(), AddFragment.AddSubscriptionListener {
} }
} }
} }