WIP: Record logs in SQLite

This commit is contained in:
Philipp Heckel 2022-01-17 00:19:05 -05:00
parent 22eeb7c719
commit 0968a39420
26 changed files with 216 additions and 58 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 6, "version": 6,
"identityHash": "fc725df9153ee7088ae8024428b7f2cf", "identityHash": "09ecfdb757b0f7643ad010fca9a0ed43",
"entities": [ "entities": [
{ {
"tableName": "Subscription", "tableName": "Subscription",
@ -195,12 +195,62 @@
}, },
"indices": [], "indices": [],
"foreignKeys": [] "foreignKeys": []
},
{
"tableName": "Logs",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `tag` TEXT NOT NULL, `level` INTEGER NOT NULL, `message` TEXT NOT NULL, `exception` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "level",
"columnName": "level",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "exception",
"columnName": "exception",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
} }
], ],
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fc725df9153ee7088ae8024428b7f2cf')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '09ecfdb757b0f7643ad010fca9a0ed43')"
] ]
} }
} }

View file

@ -4,9 +4,13 @@ import android.app.Application
import android.content.Context import android.content.Context
import io.heckel.ntfy.data.Database import io.heckel.ntfy.data.Database
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.log.Log
class Application : Application() { class Application : Application() {
private val database by lazy { Database.getInstance(this) } private val database by lazy {
Log.init(this) // What a hack, but this is super early and used everywhere
Database.getInstance(this)
}
val repository by lazy { val repository by lazy {
val sharedPrefs = applicationContext.getSharedPreferences(Repository.SHARED_PREFS_ID, Context.MODE_PRIVATE) val sharedPrefs = applicationContext.getSharedPreferences(Repository.SHARED_PREFS_ID, Context.MODE_PRIVATE)
Repository.getInstance(sharedPrefs, database.subscriptionDao(), database.notificationDao()) Repository.getInstance(sharedPrefs, database.subscriptionDao(), database.notificationDao())

View file

@ -77,10 +77,24 @@ const val PROGRESS_FAILED = -3
const val PROGRESS_DELETED = -4 const val PROGRESS_DELETED = -4
const val PROGRESS_DONE = 100 const val PROGRESS_DONE = 100
@androidx.room.Database(entities = [Subscription::class, Notification::class], version = 6) @Entity
data class Logs(
@PrimaryKey(autoGenerate = true) val id: Long, // Internal ID, only used in Repository and activities
@ColumnInfo(name = "timestamp") val timestamp: Long,
@ColumnInfo(name = "tag") val tag: String,
@ColumnInfo(name = "level") val level: Int,
@ColumnInfo(name = "message") val message: String,
@ColumnInfo(name = "exception") val exception: String?
) {
constructor(timestamp: Long, tag: String, level: Int, message: String, exception: String?) :
this(0, timestamp, tag, level, message, exception)
}
@androidx.room.Database(entities = [Subscription::class, Notification::class, Logs::class], version = 6)
abstract class Database : RoomDatabase() { abstract class Database : RoomDatabase() {
abstract fun subscriptionDao(): SubscriptionDao abstract fun subscriptionDao(): SubscriptionDao
abstract fun notificationDao(): NotificationDao abstract fun notificationDao(): NotificationDao
abstract fun logsDao(): LogsDao
companion object { companion object {
@Volatile @Volatile
@ -261,3 +275,13 @@ interface NotificationDao {
@Query("DELETE FROM notification WHERE subscriptionId = :subscriptionId") @Query("DELETE FROM notification WHERE subscriptionId = :subscriptionId")
fun removeAll(subscriptionId: Long) fun removeAll(subscriptionId: Long)
} }
@Dao
interface LogsDao {
@Insert
suspend fun insert(entry: Logs)
@Query("DELETE FROM logs WHERE id NOT IN (SELECT id FROM logs ORDER BY id DESC LIMIT :keepCount)")
suspend fun prune(keepCount: Int)
}

View file

@ -4,9 +4,9 @@ import android.app.Activity
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build import android.os.Build
import android.util.Log
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.lifecycle.* import androidx.lifecycle.*
import io.heckel.ntfy.log.Log
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong

View file

@ -0,0 +1,81 @@
package io.heckel.ntfy.log
import android.content.Context
import io.heckel.ntfy.data.Database
import io.heckel.ntfy.data.Logs
import io.heckel.ntfy.data.LogsDao
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
class Log(private val logsDao: LogsDao) {
private var record: AtomicBoolean = AtomicBoolean(false)
private var count: AtomicInteger = AtomicInteger(0)
private fun log(level: Int, tag: String, message: String, exception: Throwable?) {
if (!record.get()) return
GlobalScope.launch(Dispatchers.IO) {
logsDao.insert(Logs(System.currentTimeMillis(), tag, level, message, exception?.stackTraceToString()))
val current = count.incrementAndGet()
if (current >= PRUNE_EVERY) {
logsDao.prune(ENTRIES_MAX)
count.set(0) // I know there is a race here, but this is good enough
}
}
}
companion object {
fun d(tag: String, message: String, exception: Throwable? = null) {
if (exception == null) android.util.Log.d(tag, message) else android.util.Log.d(tag, message, exception)
getInstance()?.log(android.util.Log.DEBUG, tag, message, exception)
}
fun i(tag: String, message: String, exception: Throwable? = null) {
if (exception == null) android.util.Log.i(tag, message) else android.util.Log.i(tag, message, exception)
getInstance()?.log(android.util.Log.INFO, tag, message, exception)
}
fun w(tag: String, message: String, exception: Throwable? = null) {
if (exception == null) android.util.Log.w(tag, message) else android.util.Log.w(tag, message, exception)
getInstance()?.log(android.util.Log.WARN, tag, message, exception)
}
fun e(tag: String, message: String, exception: Throwable? = null) {
if (exception == null) android.util.Log.e(tag, message) else android.util.Log.e(tag, message, exception)
getInstance()?.log(android.util.Log.ERROR, tag, message, exception)
}
fun setRecord(enable: Boolean) {
if (!enable) d(TAG, "Disabled log recording")
getInstance()?.record?.set(enable)
if (enable) d(TAG, "Enabled log recording")
}
fun getRecord(): Boolean {
return getInstance()?.record?.get() ?: false
}
fun init(context: Context): Log {
return synchronized(Log::class) {
if (instance == null) {
val database = Database.getInstance(context.applicationContext)
instance = Log(database.logsDao())
}
instance!!
}
}
private const val TAG = "NtfyLog"
private const val PRUNE_EVERY = 100
private const val ENTRIES_MAX = 10000
private var instance: Log? = null
private fun getInstance(): Log? {
return synchronized(Log::class) {
instance
}
}
}
}

View file

@ -1,9 +1,9 @@
package io.heckel.ntfy.msg package io.heckel.ntfy.msg
import android.os.Build import android.os.Build
import android.util.Log
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.util.* import io.heckel.ntfy.util.*
import okhttp3.* import okhttp3.*
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody

View file

@ -2,10 +2,10 @@ package io.heckel.ntfy.msg
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.util.joinTagsMap import io.heckel.ntfy.util.joinTagsMap
import io.heckel.ntfy.util.splitTags import io.heckel.ntfy.util.splitTags
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View file

@ -1,11 +1,11 @@
package io.heckel.ntfy.msg package io.heckel.ntfy.msg
import android.content.Context import android.content.Context
import android.util.Log
import androidx.work.ExistingWorkPolicy import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.workDataOf import androidx.work.workDataOf
import io.heckel.ntfy.log.Log
/** /**
* Download attachment in the background via WorkManager * Download attachment in the background via WorkManager

View file

@ -25,7 +25,6 @@ import okhttp3.Response
import java.io.File import java.io.File
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class DownloadWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) { class DownloadWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
private val client = OkHttpClient.Builder() private val client = OkHttpClient.Builder()
.callTimeout(15, TimeUnit.MINUTES) // Total timeout for entire request .callTimeout(15, TimeUnit.MINUTES) // Total timeout for entire request

View file

@ -6,20 +6,15 @@ import android.graphics.BitmapFactory
import android.media.RingtoneManager import android.media.RingtoneManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.* import io.heckel.ntfy.data.*
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.ui.DetailActivity import io.heckel.ntfy.ui.DetailActivity
import io.heckel.ntfy.ui.DetailAdapter
import io.heckel.ntfy.ui.MainActivity import io.heckel.ntfy.ui.MainActivity
import io.heckel.ntfy.util.* import io.heckel.ntfy.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class NotificationService(val context: Context) { class NotificationService(val context: Context) {
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

View file

@ -0,0 +1,8 @@
package io.heckel.ntfy.service
interface Connection {
fun start()
fun close()
fun since(): Long
fun matches(otherSubscriptionIds: Collection<Long>): Boolean
}

View file

@ -8,7 +8,6 @@ import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import android.os.SystemClock import android.os.SystemClock
import android.util.Log
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
@ -17,6 +16,7 @@ import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.data.ConnectionState
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationDispatcher import io.heckel.ntfy.msg.NotificationDispatcher
import io.heckel.ntfy.ui.MainActivity import io.heckel.ntfy.ui.MainActivity
@ -26,7 +26,6 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
/** /**
* The subscriber service manages the foreground service for instant delivery. * The subscriber service manages the foreground service for instant delivery.
* *
@ -55,14 +54,6 @@ import java.util.concurrent.ConcurrentHashMap
* - https://github.com/robertohuertasm/endless-service/blob/master/app/src/main/java/com/robertohuertas/endless/EndlessService.kt * - https://github.com/robertohuertasm/endless-service/blob/master/app/src/main/java/com/robertohuertas/endless/EndlessService.kt
* - https://gist.github.com/varunon9/f2beec0a743c96708eb0ef971a9ff9cd * - https://gist.github.com/varunon9/f2beec0a743c96708eb0ef971a9ff9cd
*/ */
interface Connection {
fun start()
fun close()
fun since(): Long
fun matches(otherSubscriptionIds: Collection<Long>): Boolean
}
class SubscriberService : Service() { class SubscriberService : Service() {
private var wakeLock: PowerManager.WakeLock? = null private var wakeLock: PowerManager.WakeLock? = null
private var isServiceStarted = false private var isServiceStarted = false

View file

@ -2,10 +2,10 @@ package io.heckel.ntfy.service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.work.* import androidx.work.*
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.log.Log
/** /**
* This class only manages the SubscriberService, i.e. it starts or stops it. * This class only manages the SubscriberService, i.e. it starts or stops it.

View file

@ -4,11 +4,11 @@ import android.app.AlarmManager
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log
import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.data.ConnectionState
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.NotificationParser import io.heckel.ntfy.msg.NotificationParser
import io.heckel.ntfy.util.topicUrl import io.heckel.ntfy.util.topicUrl
import io.heckel.ntfy.util.topicUrlWs import io.heckel.ntfy.util.topicUrlWs

View file

@ -6,7 +6,6 @@ import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.Log
import android.view.View import android.view.View
import android.widget.* import android.widget.*
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@ -15,12 +14,10 @@ import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Database
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Repository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class AddFragment : DialogFragment() { class AddFragment : DialogFragment() {
private lateinit var repository: Repository private lateinit var repository: Repository
private lateinit var subscribeListener: SubscribeListener private lateinit var subscribeListener: SubscribeListener

View file

@ -6,7 +6,6 @@ import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Html import android.text.Html
import android.util.Log
import android.view.ActionMode import android.view.ActionMode
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -24,6 +23,7 @@ import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.firebase.FirebaseMessenger
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationService import io.heckel.ntfy.msg.NotificationService
import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.service.SubscriberServiceManager

View file

@ -8,7 +8,6 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -21,6 +20,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.stfalcon.imageviewer.StfalconImageViewer import com.stfalcon.imageviewer.StfalconImageViewer
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.* import io.heckel.ntfy.data.*
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.DownloadManager import io.heckel.ntfy.msg.DownloadManager
import io.heckel.ntfy.util.* import io.heckel.ntfy.util.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View file

@ -1,19 +1,18 @@
package io.heckel.ntfy.ui package io.heckel.ntfy.ui
import android.Manifest
import android.animation.Animator import android.animation.Animator
import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.view.ActionMode
import android.view.* import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -22,15 +21,19 @@ import androidx.work.*
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.util.topicShortUrl
import io.heckel.ntfy.work.PollWorker
import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.firebase.FirebaseMessenger
import io.heckel.ntfy.msg.* import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationDispatcher
import io.heckel.ntfy.service.SubscriberService import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.fadeStatusBarColor import io.heckel.ntfy.util.fadeStatusBarColor
import io.heckel.ntfy.util.formatDateShort import io.heckel.ntfy.util.formatDateShort
import kotlinx.coroutines.* import io.heckel.ntfy.util.topicShortUrl
import io.heckel.ntfy.work.PollWorker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.random.Random import kotlin.random.Random
@ -60,6 +63,9 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
Log.init(this)
Log.setRecord(true)
Log.d(TAG, "Create $this") Log.d(TAG, "Create $this")
// Dependencies that depend on Context // Dependencies that depend on Context

View file

@ -4,7 +4,6 @@ import android.app.AlertDialog
import android.app.Dialog import android.app.Dialog
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.widget.RadioButton import android.widget.RadioButton
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope

View file

@ -1,12 +1,14 @@
package io.heckel.ntfy.ui package io.heckel.ntfy.ui
import android.Manifest import android.Manifest
import android.content.* import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
@ -16,9 +18,8 @@ import androidx.preference.*
import androidx.preference.Preference.OnPreferenceClickListener import androidx.preference.Preference.OnPreferenceClickListener
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Database
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.service.SubscriberService import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.util.formatBytes import io.heckel.ntfy.util.formatBytes
import io.heckel.ntfy.util.formatDateShort import io.heckel.ntfy.util.formatDateShort

View file

@ -2,11 +2,10 @@ package io.heckel.ntfy.up
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log
import androidx.preference.PreferenceManager
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.randomString import io.heckel.ntfy.util.randomString
import io.heckel.ntfy.util.topicUrlUp import io.heckel.ntfy.util.topicUrlUp
@ -25,6 +24,7 @@ class BroadcastReceiver : android.content.BroadcastReceiver() {
if (context == null || intent == null) { if (context == null || intent == null) {
return return
} }
Log.init(context) // Init in all entrypoints
when (intent.action) { when (intent.action) {
ACTION_REGISTER -> register(context, intent) ACTION_REGISTER -> register(context, intent)
ACTION_UNREGISTER -> unregister(context, intent) ACTION_UNREGISTER -> unregister(context, intent)

View file

@ -6,17 +6,14 @@ package io.heckel.ntfy.up
*/ */
const val ACTION_NEW_ENDPOINT = "org.unifiedpush.android.connector.NEW_ENDPOINT" const val ACTION_NEW_ENDPOINT = "org.unifiedpush.android.connector.NEW_ENDPOINT"
const val ACTION_REGISTRATION_FAILED = "org.unifiedpush.android.connector.REGISTRATION_FAILED"
const val ACTION_REGISTRATION_REFUSED = "org.unifiedpush.android.connector.REGISTRATION_REFUSED" const val ACTION_REGISTRATION_REFUSED = "org.unifiedpush.android.connector.REGISTRATION_REFUSED"
const val ACTION_UNREGISTERED = "org.unifiedpush.android.connector.UNREGISTERED" const val ACTION_UNREGISTERED = "org.unifiedpush.android.connector.UNREGISTERED"
const val ACTION_MESSAGE = "org.unifiedpush.android.connector.MESSAGE" const val ACTION_MESSAGE = "org.unifiedpush.android.connector.MESSAGE"
const val ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER" const val ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER"
const val ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER" const val ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER"
const val ACTION_MESSAGE_ACK = "org.unifiedpush.android.distributor.MESSAGE_ACK"
const val EXTRA_APPLICATION = "application" const val EXTRA_APPLICATION = "application"
const val EXTRA_TOKEN = "token" const val EXTRA_TOKEN = "token"
const val EXTRA_ENDPOINT = "endpoint" const val EXTRA_ENDPOINT = "endpoint"
const val EXTRA_MESSAGE = "message" const val EXTRA_MESSAGE = "message"
const val EXTRA_MESSAGE_ID = "id"

View file

@ -2,7 +2,7 @@ package io.heckel.ntfy.up
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log import io.heckel.ntfy.log.Log
/** /**
* This is the UnifiedPush distributor, an amalgamation of messages to be sent as part of the spec. * This is the UnifiedPush distributor, an amalgamation of messages to be sent as part of the spec.

View file

@ -1,17 +1,14 @@
package io.heckel.ntfy.work package io.heckel.ntfy.work
import android.content.Context import android.content.Context
import android.util.Log
import androidx.work.CoroutineWorker import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.data.Database import io.heckel.ntfy.data.Database
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.firebase.FirebaseService import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.BroadcastService
import io.heckel.ntfy.msg.NotificationDispatcher import io.heckel.ntfy.msg.NotificationDispatcher
import io.heckel.ntfy.msg.NotificationService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlin.random.Random import kotlin.random.Random
@ -21,7 +18,12 @@ class PollWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx,
// Every time the worker is changed, the periodic work has to be REPLACEd. // Every time the worker is changed, the periodic work has to be REPLACEd.
// This is facilitated in the MainActivity using the VERSION below. // This is facilitated in the MainActivity using the VERSION below.
init {
Log.init(ctx) // Init in all entrypoints
}
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
Log.d(TAG, "Polling for new notifications") Log.d(TAG, "Polling for new notifications")
val database = Database.getInstance(applicationContext) val database = Database.getInstance(applicationContext)

View file

@ -1,7 +1,7 @@
package io.heckel.ntfy.firebase package io.heckel.ntfy.firebase
import android.util.Log
import com.google.firebase.messaging.FirebaseMessaging import com.google.firebase.messaging.FirebaseMessaging
import io.heckel.ntfy.log.Log
class FirebaseMessenger { class FirebaseMessenger {
fun subscribe(topic: String) { fun subscribe(topic: String) {

View file

@ -1,7 +1,6 @@
package io.heckel.ntfy.firebase package io.heckel.ntfy.firebase
import android.content.Intent import android.content.Intent
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage import com.google.firebase.messaging.RemoteMessage
import io.heckel.ntfy.R import io.heckel.ntfy.R
@ -9,6 +8,7 @@ import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Attachment import io.heckel.ntfy.data.Attachment
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.data.PROGRESS_NONE import io.heckel.ntfy.data.PROGRESS_NONE
import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.* import io.heckel.ntfy.msg.*
import io.heckel.ntfy.service.SubscriberService import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.util.toPriority import io.heckel.ntfy.util.toPriority
@ -23,6 +23,10 @@ class FirebaseService : FirebaseMessagingService() {
private val job = SupervisorJob() private val job = SupervisorJob()
private val messenger = FirebaseMessenger() private val messenger = FirebaseMessenger()
init {
Log.init(this) // Init in all entrypoints
}
override fun onMessageReceived(remoteMessage: RemoteMessage) { override fun onMessageReceived(remoteMessage: RemoteMessage) {
// We only process data messages // We only process data messages
if (remoteMessage.data.isEmpty()) { if (remoteMessage.data.isEmpty()) {