Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
|
debba63a5d |
6 changed files with 52 additions and 6 deletions
|
@ -10,6 +10,7 @@
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <!-- Only required on SDK <= 28 -->
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <!-- Only required on SDK <= 28 -->
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <!-- To install packages downloaded through ntfy; craazyy! -->
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <!-- To install packages downloaded through ntfy; craazyy! -->
|
||||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <!-- To reschedule the websocket retry -->
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <!-- To reschedule the websocket retry -->
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" /> <!-- To override DND -->
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".app.Application"
|
android:name=".app.Application"
|
||||||
|
|
|
@ -218,6 +218,11 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
||||||
return sharedPrefs.getInt(SHARED_PREFS_MIN_PRIORITY, 1) // 1/low means all priorities
|
return sharedPrefs.getInt(SHARED_PREFS_MIN_PRIORITY, 1) // 1/low means all priorities
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getDnsOverridePriority(): Int {
|
||||||
|
return sharedPrefs.getInt(SHARED_PREFS_DND_OVERRIDE_PRIORITY, 5)
|
||||||
|
}
|
||||||
|
|
||||||
fun getAutoDownloadMaxSize(): Long {
|
fun getAutoDownloadMaxSize(): Long {
|
||||||
val defaultValue = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
val defaultValue = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||||
AUTO_DOWNLOAD_NEVER // Need to request permission on older versions
|
AUTO_DOWNLOAD_NEVER // Need to request permission on older versions
|
||||||
|
@ -435,6 +440,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
||||||
const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion"
|
const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion"
|
||||||
const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil"
|
const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil"
|
||||||
const val SHARED_PREFS_MIN_PRIORITY = "MinPriority"
|
const val SHARED_PREFS_MIN_PRIORITY = "MinPriority"
|
||||||
|
const val SHARED_PREFS_DND_OVERRIDE_PRIORITY = "DndOverridePriority"
|
||||||
const val SHARED_PREFS_AUTO_DOWNLOAD_MAX_SIZE = "AutoDownload"
|
const val SHARED_PREFS_AUTO_DOWNLOAD_MAX_SIZE = "AutoDownload"
|
||||||
const val SHARED_PREFS_AUTO_DELETE_SECONDS = "AutoDelete"
|
const val SHARED_PREFS_AUTO_DELETE_SECONDS = "AutoDelete"
|
||||||
const val SHARED_PREFS_CONNECTION_PROTOCOL = "ConnectionProtocol"
|
const val SHARED_PREFS_CONNECTION_PROTOCOL = "ConnectionProtocol"
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package io.heckel.ntfy.msg
|
package io.heckel.ntfy.msg
|
||||||
|
|
||||||
import android.app.*
|
import android.app.NotificationChannel
|
||||||
import android.content.*
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.app.TaskStackBuilder
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.media.RingtoneManager
|
import android.media.RingtoneManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -10,15 +14,15 @@ 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.db.*
|
import io.heckel.ntfy.db.*
|
||||||
import io.heckel.ntfy.db.Notification
|
|
||||||
import io.heckel.ntfy.util.Log
|
|
||||||
import io.heckel.ntfy.ui.Colors
|
import io.heckel.ntfy.ui.Colors
|
||||||
import io.heckel.ntfy.ui.DetailActivity
|
import io.heckel.ntfy.ui.DetailActivity
|
||||||
import io.heckel.ntfy.ui.MainActivity
|
import io.heckel.ntfy.ui.MainActivity
|
||||||
import io.heckel.ntfy.util.*
|
import io.heckel.ntfy.util.*
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
private val repository = Repository.getInstance(context)
|
||||||
|
|
||||||
fun display(subscription: Subscription, notification: Notification) {
|
fun display(subscription: Subscription, notification: Notification) {
|
||||||
Log.d(TAG, "Displaying notification $notification")
|
Log.d(TAG, "Displaying notification $notification")
|
||||||
|
@ -218,6 +222,7 @@ class NotificationService(val context: Context) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
// Note: To change a notification channel, you must delete the old one and create a new one!
|
// Note: To change a notification channel, you must delete the old one and create a new one!
|
||||||
|
|
||||||
|
val dndOverridePriority = repository.getDnsOverridePriority()
|
||||||
val pause = 300L
|
val pause = 300L
|
||||||
val channel = when (priority) {
|
val channel = when (priority) {
|
||||||
1 -> NotificationChannel(CHANNEL_ID_MIN, context.getString(R.string.channel_notifications_min_name), NotificationManager.IMPORTANCE_MIN)
|
1 -> NotificationChannel(CHANNEL_ID_MIN, context.getString(R.string.channel_notifications_min_name), NotificationManager.IMPORTANCE_MIN)
|
||||||
|
@ -225,6 +230,7 @@ class NotificationService(val context: Context) {
|
||||||
4 -> {
|
4 -> {
|
||||||
val channel = NotificationChannel(CHANNEL_ID_HIGH, context.getString(R.string.channel_notifications_high_name), NotificationManager.IMPORTANCE_HIGH)
|
val channel = NotificationChannel(CHANNEL_ID_HIGH, context.getString(R.string.channel_notifications_high_name), NotificationManager.IMPORTANCE_HIGH)
|
||||||
channel.enableVibration(true)
|
channel.enableVibration(true)
|
||||||
|
channel.setBypassDnd(dndOverridePriority >= 4)
|
||||||
channel.vibrationPattern = longArrayOf(
|
channel.vibrationPattern = longArrayOf(
|
||||||
pause, 100, pause, 100, pause, 100,
|
pause, 100, pause, 100, pause, 100,
|
||||||
pause, 2000
|
pause, 2000
|
||||||
|
@ -235,6 +241,7 @@ class NotificationService(val context: Context) {
|
||||||
val channel = NotificationChannel(CHANNEL_ID_MAX, context.getString(R.string.channel_notifications_max_name), NotificationManager.IMPORTANCE_HIGH) // IMPORTANCE_MAX does not exist
|
val channel = NotificationChannel(CHANNEL_ID_MAX, context.getString(R.string.channel_notifications_max_name), NotificationManager.IMPORTANCE_HIGH) // IMPORTANCE_MAX does not exist
|
||||||
channel.enableLights(true)
|
channel.enableLights(true)
|
||||||
channel.enableVibration(true)
|
channel.enableVibration(true)
|
||||||
|
channel.setBypassDnd(dndOverridePriority >= 4)
|
||||||
channel.vibrationPattern = longArrayOf(
|
channel.vibrationPattern = longArrayOf(
|
||||||
pause, 100, pause, 100, pause, 100,
|
pause, 100, pause, 100, pause, 100,
|
||||||
pause, 2000,
|
pause, 2000,
|
||||||
|
|
|
@ -30,7 +30,6 @@ import io.heckel.ntfy.app.Application
|
||||||
import io.heckel.ntfy.db.Repository
|
import io.heckel.ntfy.db.Repository
|
||||||
import io.heckel.ntfy.db.Subscription
|
import io.heckel.ntfy.db.Subscription
|
||||||
import io.heckel.ntfy.firebase.FirebaseMessenger
|
import io.heckel.ntfy.firebase.FirebaseMessenger
|
||||||
import io.heckel.ntfy.util.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.service.SubscriberService
|
import io.heckel.ntfy.service.SubscriberService
|
||||||
|
@ -376,7 +375,9 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.main_menu_docs -> {
|
R.id.main_menu_docs -> {
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_docs_url))))
|
//startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_docs_url))))
|
||||||
|
val intent = Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS)
|
||||||
|
startActivity(intent)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.heckel.ntfy.ui
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -120,6 +121,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
||||||
class SettingsFragment : PreferenceFragmentCompat() {
|
class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
private lateinit var repository: Repository
|
private lateinit var repository: Repository
|
||||||
private lateinit var serviceManager: SubscriberServiceManager
|
private lateinit var serviceManager: SubscriberServiceManager
|
||||||
|
private lateinit var notificationManager: NotificationManager
|
||||||
private var autoDownloadSelection = AUTO_DOWNLOAD_SELECTION_NOT_SET
|
private var autoDownloadSelection = AUTO_DOWNLOAD_SELECTION_NOT_SET
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
@ -129,6 +131,7 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
||||||
repository = Repository.getInstance(requireActivity())
|
repository = Repository.getInstance(requireActivity())
|
||||||
serviceManager = SubscriberServiceManager(requireActivity())
|
serviceManager = SubscriberServiceManager(requireActivity())
|
||||||
autoDownloadSelection = repository.getAutoDownloadMaxSize() // Only used for <= Android P, due to permissions request
|
autoDownloadSelection = repository.getAutoDownloadMaxSize() // Only used for <= Android P, due to permissions request
|
||||||
|
notificationManager = requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
// Important note: We do not use the default shared prefs to store settings. Every
|
// Important note: We do not use the default shared prefs to store settings. Every
|
||||||
// preferenceDataStore is overridden to use the repository. This is convenient, because
|
// preferenceDataStore is overridden to use the repository. This is convenient, because
|
||||||
|
@ -200,6 +203,33 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DND override priority
|
||||||
|
val dndOverrideEnabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && notificationManager.isNotificationPolicyAccessGranted
|
||||||
|
val dndOverridePriorityPrefId = context?.getString(R.string.settings_notifications_dnd_override_priority_key) ?: return
|
||||||
|
val dndOverridePriority: ListPreference? = findPreference(minPriorityPrefId)
|
||||||
|
dndOverridePriority?.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
|
dndOverridePriority?.value = repository.getDnsOverridePriority().toString()
|
||||||
|
dndOverridePriority?.preferenceDataStore = object : PreferenceDataStore() {
|
||||||
|
override fun putString(key: String?, value: String?) {
|
||||||
|
val dndOverridePriorityValue = value?.toIntOrNull() ?:return
|
||||||
|
//repository.setMinPriority(minPriorityValue)
|
||||||
|
}
|
||||||
|
override fun getString(key: String?, defValue: String?): String {
|
||||||
|
return repository.getDnsOverridePriority().toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dndOverridePriority?.summaryProvider = Preference.SummaryProvider<ListPreference> { pref ->
|
||||||
|
val priorityValue = pref.value.toIntOrNull() ?: 1 // 1/low means all priorities
|
||||||
|
when (priorityValue) {
|
||||||
|
1 -> getString(R.string.settings_notifications_min_priority_summary_any)
|
||||||
|
5 -> getString(R.string.settings_notifications_min_priority_summary_max)
|
||||||
|
else -> {
|
||||||
|
val minPriorityString = toPriorityString(requireContext(), priorityValue)
|
||||||
|
getString(R.string.settings_notifications_min_priority_summary_x_or_higher, priorityValue, minPriorityString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Auto download
|
// Auto download
|
||||||
val autoDownloadPrefId = context?.getString(R.string.settings_notifications_auto_download_key) ?: return
|
val autoDownloadPrefId = context?.getString(R.string.settings_notifications_auto_download_key) ?: return
|
||||||
val autoDownload: ListPreference? = findPreference(autoDownloadPrefId)
|
val autoDownload: ListPreference? = findPreference(autoDownloadPrefId)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<!-- Settings constants -->
|
<!-- Settings constants -->
|
||||||
<string name="settings_notifications_muted_until_key" translatable="false">MutedUntil</string>
|
<string name="settings_notifications_muted_until_key" translatable="false">MutedUntil</string>
|
||||||
<string name="settings_notifications_min_priority_key" translatable="false">MinPriority</string>
|
<string name="settings_notifications_min_priority_key" translatable="false">MinPriority</string>
|
||||||
|
<string name="settings_notifications_dnd_override_priority_key" translatable="false">DndOverridePriority</string>
|
||||||
<string name="settings_notifications_auto_download_key" translatable="false">AutoDownload</string>
|
<string name="settings_notifications_auto_download_key" translatable="false">AutoDownload</string>
|
||||||
<string name="settings_notifications_auto_delete_key" translatable="false">AutoDelete</string>
|
<string name="settings_notifications_auto_delete_key" translatable="false">AutoDelete</string>
|
||||||
<string name="settings_general_default_base_url_key" translatable="false">DefaultBaseURL</string>
|
<string name="settings_general_default_base_url_key" translatable="false">DefaultBaseURL</string>
|
||||||
|
|
Loading…
Reference in a new issue