aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorPhilipp Heckel <pheckel@datto.com>2022-11-29 22:46:38 -0500
committerPhilipp Heckel <pheckel@datto.com>2022-11-29 22:46:38 -0500
commit55ad2e65b5a7ea521bf8bcc211f563ae9f9d4e8c (patch)
tree673b12db5885832ec1169e65a497e9f808f028e8 /app
parente18be4a2a79b3d16aefd5113d2df2274d683e60b (diff)
downloadponypush-55ad2e65b5a7ea521bf8bcc211f563ae9f9d4e8c.tar.gz
ponypush-55ad2e65b5a7ea521bf8bcc211f563ae9f9d4e8c.tar.bz2
ponypush-55ad2e65b5a7ea521bf8bcc211f563ae9f9d4e8c.zip
Works!
Diffstat (limited to 'app')
-rw-r--r--app/src/main/AndroidManifest.xml7
-rw-r--r--app/src/main/java/io/heckel/ntfy/app/Application.kt6
-rw-r--r--app/src/main/java/io/heckel/ntfy/db/Repository.kt15
-rw-r--r--app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt103
-rw-r--r--app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt1
-rw-r--r--app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt20
-rw-r--r--app/src/main/res/values/strings.xml3
-rw-r--r--app/src/main/res/values/values.xml1
-rw-r--r--app/src/main/res/xml/main_preferences.xml4
9 files changed, 98 insertions, 62 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 35689fd..8120b56 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -134,7 +134,12 @@
android:exported="false">
</receiver>
- <receiver android:name=".msg.NotificationService$AlarmReceiver"/>
+ <!-- Broadcast receiver for when the notification is swiped away (currently only to cancel the insistent sound) -->
+ <receiver
+ android:name=".msg.NotificationService$DeleteBroadcastReceiver"
+ android:enabled="true"
+ android:exported="false">
+ </receiver>
<!-- Firebase messaging (note that this is empty in the F-Droid flavor) -->
<service
diff --git a/app/src/main/java/io/heckel/ntfy/app/Application.kt b/app/src/main/java/io/heckel/ntfy/app/Application.kt
index b4b104c..f6cb30c 100644
--- a/app/src/main/java/io/heckel/ntfy/app/Application.kt
+++ b/app/src/main/java/io/heckel/ntfy/app/Application.kt
@@ -1,16 +1,10 @@
package io.heckel.ntfy.app
import android.app.Application
-import android.content.Context
-import io.heckel.ntfy.db.Database
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.util.Log
class Application : Application() {
- 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 = Repository.getInstance(applicationContext)
if (repository.getRecordLogs()) {
diff --git a/app/src/main/java/io/heckel/ntfy/db/Repository.kt b/app/src/main/java/io/heckel/ntfy/db/Repository.kt
index cee2985..d92e4a8 100644
--- a/app/src/main/java/io/heckel/ntfy/db/Repository.kt
+++ b/app/src/main/java/io/heckel/ntfy/db/Repository.kt
@@ -2,6 +2,7 @@ package io.heckel.ntfy.db
import android.content.Context
import android.content.SharedPreferences
+import android.media.MediaPlayer
import android.os.Build
import androidx.annotation.WorkerThread
import androidx.appcompat.app.AppCompatDelegate
@@ -18,7 +19,10 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
private val connectionStates = ConcurrentHashMap<Long, ConnectionState>()
private val connectionStatesLiveData = MutableLiveData(connectionStates)
+
+ // TODO Move these into an ApplicationState singleton
val detailViewSubscriptionId = AtomicLong(0L) // Omg, what a hack ...
+ val mediaPlayer = MediaPlayer()
init {
Log.d(TAG, "Created $this")
@@ -288,6 +292,16 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
.apply()
}
+ fun getInsistentMaxPriorityEnabled(): Boolean {
+ return sharedPrefs.getBoolean(SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED, false) // Disabled by default
+ }
+
+ fun setInsistentMaxPriorityEnabled(enabled: Boolean) {
+ sharedPrefs.edit()
+ .putBoolean(SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED, enabled)
+ .apply()
+ }
+
fun getRecordLogs(): Boolean {
return sharedPrefs.getBoolean(SHARED_PREFS_RECORD_LOGS_ENABLED, false) // Disabled by default
}
@@ -459,6 +473,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
const val SHARED_PREFS_CONNECTION_PROTOCOL = "ConnectionProtocol"
const val SHARED_PREFS_DARK_MODE = "DarkMode"
const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled"
+ const val SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED = "InsistentMaxPriority"
const val SHARED_PREFS_RECORD_LOGS_ENABLED = "RecordLogs"
const val SHARED_PREFS_BATTERY_OPTIMIZATIONS_REMIND_TIME = "BatteryOptimizationsRemindTime"
const val SHARED_PREFS_WEBSOCKET_REMIND_TIME = "JsonStreamRemindTime" // "Use WebSocket" banner (used to be JSON stream deprecation banner)
diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt
index a2adb41..6f46ca6 100644
--- a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt
+++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt
@@ -7,7 +7,6 @@ import android.content.Context
import android.content.Intent
import android.media.AudioAttributes
import android.media.AudioManager
-import android.media.MediaPlayer
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
@@ -24,9 +23,9 @@ import io.heckel.ntfy.ui.MainActivity
import io.heckel.ntfy.util.*
import java.util.*
-
class NotificationService(val context: Context) {
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ private val repository = Repository.getInstance(context)
fun display(subscription: Subscription, notification: Notification) {
Log.d(TAG, "Displaying notification $notification")
@@ -66,6 +65,7 @@ class NotificationService(val context: Context) {
private fun displayInternal(subscription: Subscription, notification: Notification, update: Boolean = false) {
val title = formatTitle(subscription, notification)
val channelId = toChannelId(notification.priority)
+ val insistent = notification.priority == 5 && repository.getInsistentMaxPriorityEnabled()
val builder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setColor(ContextCompat.getColor(context, Colors.notificationIcon(context)))
@@ -74,7 +74,8 @@ class NotificationService(val context: Context) {
.setAutoCancel(true) // Cancel when notification is clicked
setStyleAndText(builder, subscription, notification) // Preview picture or big text style
setClickAction(builder, subscription, notification)
- maybeSetSound(builder, update)
+ maybeSetDeleteIntent(builder, insistent)
+ maybeSetSound(builder, insistent, update)
maybeSetProgress(builder, notification)
maybeAddOpenAction(builder, notification)
maybeAddBrowseAction(builder, notification)
@@ -82,65 +83,24 @@ class NotificationService(val context: Context) {
maybeAddCancelAction(builder, notification)
maybeAddUserActions(builder, notification)
-
-
maybeCreateNotificationChannel(notification.priority)
- val systemNotification = builder.build()
- if (channelId == CHANNEL_ID_MAX) {
- //systemNotification.flags = systemNotification.flags or android.app.Notification.FLAG_INSISTENT
- }
- notificationManager.notify(notification.notificationId, systemNotification)
-
- if (channelId == CHANNEL_ID_MAX) {
- Log.d(TAG, "Setting alarm")
- /*val calendar = Calendar.getInstance()
- val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
- val intent = Intent(context, AlarmReceiver::class.java)
- val pendingIntent = PendingIntent.getBroadcast(context, 1111, intent, PendingIntent.FLAG_IMMUTABLE)
- // when using setAlarmClock() it displays a notification until alarm rings and when pressed it takes us to mainActivity
-
- alarmManager?.set(
- AlarmManager.RTC_WAKEUP,
- calendar.timeInMillis, pendingIntent
- )*/
-
- val alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
- val mMediaPlayer = MediaPlayer()
-
- mMediaPlayer.setDataSource(context, alert)
- val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
- if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
- mMediaPlayer.setAudioAttributes(AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).build())
- mMediaPlayer.isLooping = true;
- mMediaPlayer.prepare();
- mMediaPlayer.start();
- mMediaPlayer.stop()
- }
+ maybePlayInsistentSound(insistent)
- }
+ notificationManager.notify(notification.notificationId, builder.build())
}
- class AlarmReceiver : BroadcastReceiver() {
- override fun onReceive(context: Context?, intent: Intent?) {
- Log.d(TAG, "AlarmReceiver.onReceive ${intent}")
- val context = context ?: return
-
- val alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
- val mMediaPlayer = MediaPlayer()
-
- mMediaPlayer.setDataSource(context, alert)
- val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
- if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
- mMediaPlayer.setLooping(true);
- mMediaPlayer.prepare();
- mMediaPlayer.start();
- }
+ private fun maybeSetDeleteIntent(builder: NotificationCompat.Builder, insistent: Boolean) {
+ if (!insistent) {
+ return
}
+ val intent = Intent(context, DeleteBroadcastReceiver::class.java)
+ val pendingIntent = PendingIntent.getBroadcast(context, Random().nextInt(), intent, PendingIntent.FLAG_IMMUTABLE)
+ builder.setDeleteIntent(pendingIntent)
}
- private fun maybeSetSound(builder: NotificationCompat.Builder, update: Boolean) {
- if (!update) {
+ private fun maybeSetSound(builder: NotificationCompat.Builder, insistent: Boolean, update: Boolean) {
+ val hasSound = !update && !insistent
+ if (hasSound) {
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
builder.setSound(defaultSoundUri)
} else {
@@ -353,6 +313,17 @@ class NotificationService(val context: Context) {
}
}
+ /**
+ * Receives a broadcast when a notification is swiped away. This is currently
+ * only called for notifications with an insistent sound.
+ */
+ class DeleteBroadcastReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val mediaPlayer = Repository.getInstance(context).mediaPlayer
+ mediaPlayer.stop()
+ }
+ }
+
private fun detailActivityIntent(subscription: Subscription): PendingIntent? {
val intent = Intent(context, DetailActivity::class.java).apply {
putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
@@ -416,6 +387,28 @@ class NotificationService(val context: Context) {
}
}
+ private fun maybePlayInsistentSound(insistent: Boolean) {
+ if (!insistent) {
+ return
+ }
+ try {
+ Log.d(TAG, "Playing insistent alarm")
+ val mediaPlayer = repository.mediaPlayer
+ val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
+ val alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
+ if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
+ mediaPlayer.reset()
+ mediaPlayer.setDataSource(context, alert)
+ mediaPlayer.setAudioAttributes(AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).build())
+ mediaPlayer.isLooping = true;
+ mediaPlayer.prepare()
+ mediaPlayer.start()
+ }
+ } catch (e: Exception) {
+ Log.w(TAG, "Failed playing insistent alarm", e)
+ }
+ }
+
/**
* Activity used to launch a URL.
* .
diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
index 4fc9ec7..0eec67b 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt
@@ -297,6 +297,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra
}
}
}
+ repository.mediaPlayer.stop()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
diff --git a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
index cc6f882..859232a 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
@@ -200,6 +200,26 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
}
+ // Keep alerting for max priority
+ val insistentMaxPriorityPrefId = context?.getString(R.string.settings_notifications_insistent_max_priority_key) ?: return
+ val insistentMaxPriority: SwitchPreference? = findPreference(insistentMaxPriorityPrefId)
+ insistentMaxPriority?.isChecked = repository.getInsistentMaxPriorityEnabled()
+ insistentMaxPriority?.preferenceDataStore = object : PreferenceDataStore() {
+ override fun putBoolean(key: String?, value: Boolean) {
+ repository.setInsistentMaxPriorityEnabled(value)
+ }
+ override fun getBoolean(key: String?, defValue: Boolean): Boolean {
+ return repository.getInsistentMaxPriorityEnabled()
+ }
+ }
+ insistentMaxPriority?.summaryProvider = Preference.SummaryProvider<SwitchPreference> { pref ->
+ if (pref.isChecked) {
+ getString(R.string.settings_notifications_insistent_max_priority_summary_enabled)
+ } else {
+ getString(R.string.settings_notifications_insistent_max_priority_summary_disabled)
+ }
+ }
+
// Channel settings
val channelPrefsPrefId = context?.getString(R.string.settings_notifications_channel_prefs_key) ?: return
val channelPrefs: Preference? = findPreference(channelPrefsPrefId)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 59c9817..b8ea38b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -279,6 +279,9 @@
<string name="settings_notifications_auto_delete_one_week">After one week</string>
<string name="settings_notifications_auto_delete_one_month">After one month</string>
<string name="settings_notifications_auto_delete_three_months">After 3 months</string>
+ <string name="settings_notifications_insistent_max_priority_title">Keep alerting for highest priority</string>
+ <string name="settings_notifications_insistent_max_priority_summary_enabled">Max priority notifications continuously play the notification sound until dismissed. This overrides Do Not Disturb mode.</string>
+ <string name="settings_notifications_insistent_max_priority_summary_disabled">Max priority notifications alert only once. If enabled, the notification sound will repeat and override Do Not Disturb mode.</string>
<string name="settings_general_header">General</string>
<string name="settings_general_default_base_url_title">Default server</string>
<string name="settings_general_default_base_url_message">Enter your server\'s root URL to use your own server as a default when subscribing to new topics and/or sharing to topics.</string>
diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml
index 2ccbda8..0b33496 100644
--- a/app/src/main/res/values/values.xml
+++ b/app/src/main/res/values/values.xml
@@ -18,6 +18,7 @@
<string name="settings_notifications_channel_prefs_key" translatable="false">ChannelPrefs</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_insistent_max_priority_key" translatable="false">InsistentMaxPriority</string>
<string name="settings_general_default_base_url_key" translatable="false">DefaultBaseURL</string>
<string name="settings_general_users_key" translatable="false">ManageUsers</string>
<string name="settings_general_dark_mode_key" translatable="false">DarkMode</string>
diff --git a/app/src/main/res/xml/main_preferences.xml b/app/src/main/res/xml/main_preferences.xml
index 42603a2..d7178a6 100644
--- a/app/src/main/res/xml/main_preferences.xml
+++ b/app/src/main/res/xml/main_preferences.xml
@@ -25,6 +25,10 @@
app:entries="@array/settings_notifications_auto_delete_entries"
app:entryValues="@array/settings_notifications_auto_delete_values"
app:defaultValue="2592000"/>
+ <SwitchPreference
+ app:key="@string/settings_notifications_insistent_max_priority_key"
+ app:title="@string/settings_notifications_insistent_max_priority_title"
+ app:defaultValue="false"/>
<Preference
app:key="@string/settings_notifications_channel_prefs_key"
app:title="@string/settings_notifications_channel_prefs_title"