FreshRSSApplication.kt 5.24 KB
Newer Older
1 2 3
package fr.chenry.android.freshrss

import android.app.Application
Christophe Henry's avatar
Christophe Henry committed
4
import android.content.*
5 6
import android.os.Handler
import android.os.IBinder
Christophe Henry's avatar
Christophe Henry committed
7
import androidx.core.app.NotificationManagerCompat
8
import androidx.core.os.postDelayed
9 10
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
Christophe Henry's avatar
Christophe Henry committed
11
import androidx.room.Room
12
import fr.chenry.android.freshrss.RefresherService.RefresherBinder
augier's avatar
augier committed
13
import fr.chenry.android.freshrss.store.FreshRSSPreferences
14
import fr.chenry.android.freshrss.store.database.FreshRSSDabatabase
Christophe Henry's avatar
Christophe Henry committed
15
import fr.chenry.android.freshrss.store.database.FreshRSSDabatabase_Migrations
16 17
import nl.komponents.kovenant.android.startKovenant
import nl.komponents.kovenant.android.stopKovenant
Christophe Henry's avatar
Christophe Henry committed
18 19 20 21
import org.acra.ACRA
import org.acra.annotation.*
import org.acra.data.StringFormat
import org.acra.sender.HttpSender
Christophe Henry's avatar
Christophe Henry committed
22
import java.util.Locale
23

Christophe Henry's avatar
Christophe Henry committed
24 25 26
@AcraCore(reportFormat = StringFormat.JSON)
@AcraHttpSender(
    uri = "https://android-report.christophe-henry.dev/report",
Christophe Henry's avatar
Christophe Henry committed
27 28
    basicAuthLogin = "4qEGdZXlUxV2vqoN",
    basicAuthPassword = "oYq9b2rumfVALboE",
Christophe Henry's avatar
Christophe Henry committed
29 30 31 32 33 34 35 36
    httpMethod = HttpSender.Method.POST
)
@AcraNotification(
    resChannelName = R.string.notification_channel_errors_reports_title,
    resText = R.string.notification_crash_description,
    resTitle = R.string.notification_crash_title,
    resChannelImportance = NotificationManagerCompat.IMPORTANCE_MAX
)
37
class FreshRSSApplication: Application() {
38
    private val _refresherService = MutableLiveData<RefresherService>()
Christophe Henry's avatar
Christophe Henry committed
39 40
    private val serviceConnection = RefresherServiceConnection()

41
    val refresherService: LiveData<RefresherService> get() = _refresherService
augier's avatar
augier committed
42
    val preferences: FreshRSSPreferences = FreshRSSPreferences(this)
43

Christophe Henry's avatar
Christophe Henry committed
44
    val database by lazy {
Christophe Henry's avatar
Christophe Henry committed
45
        val dbName = "${context.getString(R.string.app_name).toLowerCase(Locale.ENGLISH)}.db"
Christophe Henry's avatar
Christophe Henry committed
46 47 48 49
        Room.databaseBuilder(context, FreshRSSDabatabase::class.java, dbName)
            .addMigrations(*FreshRSSDabatabase_Migrations.build())
            .build()
    }
50

Christophe Henry's avatar
Christophe Henry committed
51 52 53 54 55
    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        ACRA.init(this)
    }

56 57
    override fun onCreate() {
        super.onCreate()
58
        startKovenant()
Christophe Henry's avatar
Christophe Henry committed
59 60
        // Stupid hack because Android is still not able to provide the current
        // application globally even though it's an actual a singleton...
61
        appInstance = this
62

augier's avatar
augier committed
63 64
        preferences.initDefaults()

65 66
        bindService(Intent(this, RefresherService::class.java), serviceConnection, Context.BIND_AUTO_CREATE)

67
        // Debug
68
        //Stetho.initializeWithDefaults(this)
69 70 71 72 73 74
    }

    override fun onTerminate() {
        super.onTerminate()
        stopKovenant()
    }
Christophe Henry's avatar
Christophe Henry committed
75 76

    companion object {
77
        private lateinit var appInstance: FreshRSSApplication
Christophe Henry's avatar
Christophe Henry committed
78 79 80
        val app: FreshRSSApplication get() = appInstance
        val db inline get() = app.database
        val context: Context inline get() = app.applicationContext
Christophe Henry's avatar
Christophe Henry committed
81
        val notificationManager: NotificationManagerCompat
Christophe Henry's avatar
Christophe Henry committed
82 83
            inline get() = NotificationManagerCompat.from(app)
        val preferences: FreshRSSPreferences inline get() = app.preferences
84

Christophe Henry's avatar
Refacto  
Christophe Henry committed
85
        fun getString(id: Int, vararg formatArgs: Any = arrayOf()): String = if(formatArgs.isEmpty())
Christophe Henry's avatar
Christophe Henry committed
86 87
            app.resources.getString(id) else
            app.resources.getString(id, *formatArgs)
88 89
    }

90
    inner class RefresherServiceConnection: ServiceConnection, SharedPreferences.OnSharedPreferenceChangeListener {
91
        private val handler = Handler()
92
        private val token = object {}
augier's avatar
augier committed
93
        private var refreshFrequency: Long = 30L
94 95

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Christophe Henry's avatar
Christophe Henry committed
96 97 98 99 100 101 102
            if(service is RefresherBinder) {
                refreshFrequency = this@FreshRSSApplication.preferences.refreshFrequency
                service.service.let {
                    _refresherService.value = it
                    this@FreshRSSApplication.preferences.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
                    postDelayedRefesh()
                }
103
            }
104 105
        }

augier's avatar
augier committed
106
        override fun onServiceDisconnected(name: ComponentName?) {
Christophe Henry's avatar
Christophe Henry committed
107
            _refresherService.value?.apply {cancelRefreshNotification()}
augier's avatar
augier committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
            handler.removeCallbacksAndMessages(token)
            this@FreshRSSApplication.preferences.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
            _refresherService.value = null
        }

        override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
            val newRefreshFrequency = this@FreshRSSApplication.preferences.refreshFrequency
            if(refreshFrequency == newRefreshFrequency) return

            refreshFrequency = newRefreshFrequency

            handler.removeCallbacksAndMessages(token)
            this.postDelayedRefesh()
        }

123
        private fun postDelayedRefesh() {
augier's avatar
augier committed
124 125 126 127
            // Deactivate when refreshFrequency is 0 meaning automatic refresh is off
            if(this.refreshFrequency == 0L) return

            handler.postDelayed(this.refreshFrequency * 60 * 1000, token) {
Christophe Henry's avatar
Refacto  
Christophe Henry committed
128
                this@FreshRSSApplication.refresherService.value?.let {
Christophe Henry's avatar
Christophe Henry committed
129
                    it.refresh(false)
130 131 132 133
                    postDelayedRefesh()
                }
            }
        }
Christophe Henry's avatar
Christophe Henry committed
134
    }
Christophe Henry's avatar
Christophe Henry committed
135
}
Christophe Henry's avatar
Refacto  
Christophe Henry committed
136 137

val F = FreshRSSApplication.Companion