diff --git a/app/src/main/java/com/orgzly/android/NotificationChannels.kt b/app/src/main/java/com/orgzly/android/NotificationChannels.kt index 0d691a895..b15499b40 100644 --- a/app/src/main/java/com/orgzly/android/NotificationChannels.kt +++ b/app/src/main/java/com/orgzly/android/NotificationChannels.kt @@ -9,6 +9,8 @@ import androidx.annotation.RequiresApi import com.orgzly.R import com.orgzly.android.reminders.RemindersNotifications import com.orgzly.android.ui.util.getNotificationManager +import com.orgzly.android.prefs.AppPreferences +import java.util.UUID /** @@ -16,15 +18,34 @@ import com.orgzly.android.ui.util.getNotificationManager */ object NotificationChannels { - const val ONGOING = "ongoing" - const val REMINDERS = "reminders" + private const val _ONGOING = "ongoing" + private var ongoingId = "" + private var prevOngoingId = _ONGOING + + private const val _REMINDERS = "reminders" + private var remindersId = "" + private var prevRemindersId = _REMINDERS + const val SYNC_PROGRESS = "sync-progress" const val SYNC_FAILED = "sync-failed" const val SYNC_PROMPT = "sync-prompt" + @JvmStatic + fun channelIdForOngoing() : String { + return ongoingId; + } + + @JvmStatic + fun channelIdForReminders() : String { + return remindersId; + } + + @JvmStatic fun createAll(context: Context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + updateChannelIds(); + createForOngoing(context) createForReminders(context) createForSyncProgress(context) @@ -33,9 +54,46 @@ object NotificationChannels { } } + @JvmStatic + fun updateAll(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + updateChannelIds(); + + updateForReminders(context) + updateForOngoing(context) + } + } + + private fun updateChannelIds() { + prevRemindersId = remindersId; + remindersId = _REMINDERS + "_" + UUID.randomUUID() + + prevOngoingId = ongoingId; + ongoingId = _ONGOING + "_" + UUID.randomUUID() + } + + @RequiresApi(Build.VERSION_CODES.O) - private fun createForReminders(context: Context) { - val id = REMINDERS + private fun updateForReminders(context: Context) { + val channel = createChannelForReminders(context); + context.getNotificationManager().createNotificationChannel(channel) + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun updateForOngoing(context: Context) { + // Note: Effect on Notifications: Deleting a notification channel will remove all + // notifications associated with that channel. If you recreate the channel later, it will be + // treated as a new channel, and any previous notifications will not be restored. Using the + // same ID will restore the previous channel including the LED color. + + val channel = createChannelForOngoing(context); + context.getNotificationManager().createNotificationChannel(channel) + } + + + @RequiresApi(Build.VERSION_CODES.O) + private fun createChannelForReminders(context: Context) : NotificationChannel { + val id = remindersId; val name = context.getString(R.string.reminders_channel_name) val description = context.getString(R.string.reminders_channel_description) val importance = NotificationManager.IMPORTANCE_HIGH @@ -45,22 +103,32 @@ object NotificationChannels { channel.description = description channel.enableLights(true) - channel.lightColor = Color.BLUE + + val colorString = AppPreferences.remindersLedColor(context); + channel.lightColor = Color.parseColor(colorString); channel.vibrationPattern = RemindersNotifications.VIBRATION_PATTERN channel.setShowBadge(false) + return channel; + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun createForReminders(context: Context) { + val channel = createChannelForReminders(context) context.getNotificationManager().createNotificationChannel(channel) } @RequiresApi(Build.VERSION_CODES.O) - private fun createForOngoing(context: Context) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - return - } + private fun createForOngoing(context: Context) { + val channel = createChannelForOngoing(context) + context.getNotificationManager().createNotificationChannel(channel) + } - val id = ONGOING + @RequiresApi(Build.VERSION_CODES.O) + private fun createChannelForOngoing(context: Context) : NotificationChannel { + val id = ongoingId val name = context.getString(R.string.ongoing_channel_name) val description = context.getString(R.string.ongoing_channel_description) val importance = NotificationManager.IMPORTANCE_MIN @@ -71,7 +139,10 @@ object NotificationChannels { channel.setShowBadge(false) - context.getNotificationManager().createNotificationChannel(channel) + val colorString = AppPreferences.remindersLedColor(context); + channel.lightColor = Color.parseColor(colorString); + + return channel; } @RequiresApi(Build.VERSION_CODES.O) diff --git a/app/src/main/java/com/orgzly/android/prefs/AppPreferences.java b/app/src/main/java/com/orgzly/android/prefs/AppPreferences.java index 4ffcb792c..6ecf3cfcb 100644 --- a/app/src/main/java/com/orgzly/android/prefs/AppPreferences.java +++ b/app/src/main/java/com/orgzly/android/prefs/AppPreferences.java @@ -329,6 +329,12 @@ public static boolean remindersLed(Context context) { context.getResources().getBoolean(R.bool.pref_default_reminders_led)); } + public static String remindersLedColor(Context context) { + return getDefaultSharedPreferences(context).getString( + context.getResources().getString(R.string.pref_key_reminders_led_color), + context.getResources().getString(R.string.pref_default_reminders_led_color)); + } + public static boolean remindersVibrate(Context context) { return getDefaultSharedPreferences(context).getBoolean( context.getResources().getString(R.string.pref_key_reminders_vibrate), diff --git a/app/src/main/java/com/orgzly/android/reminders/RemindersNotifications.kt b/app/src/main/java/com/orgzly/android/reminders/RemindersNotifications.kt index 6c3e83f92..17bdb4926 100644 --- a/app/src/main/java/com/orgzly/android/reminders/RemindersNotifications.kt +++ b/app/src/main/java/com/orgzly/android/reminders/RemindersNotifications.kt @@ -26,7 +26,8 @@ import com.orgzly.android.util.UserTimeFormatter object RemindersNotifications { val VIBRATION_PATTERN = longArrayOf(500, 50, 50, 300) - private val LIGHTS = Triple(Color.BLUE, 1000, 5000) + private val LIGHTS_ON_MS = 1000 + private val LIGHTS_OFF_MS = 5000 fun showNotifications(context: Context, notes: List, logs: AppLogsRepository) { val notificationManager = context.getNotificationManager() @@ -38,7 +39,8 @@ object RemindersNotifications { val content = getContent(context, noteReminder) - val builder = NotificationCompat.Builder(context, NotificationChannels.REMINDERS) + val builder = NotificationCompat.Builder(context, + NotificationChannels.channelIdForReminders()) .setAutoCancel(true) .setCategory(NotificationCompat.CATEGORY_REMINDER) .setPriority(NotificationCompat.PRIORITY_MAX) @@ -61,7 +63,9 @@ object RemindersNotifications { // Set LED if (AppPreferences.remindersLed(context)) { - builder.setLights(LIGHTS.first, LIGHTS.second, LIGHTS.third) + val colorString = AppPreferences.remindersLedColor(context); + val color = Color.parseColor(colorString); + builder.setLights(color, LIGHTS_ON_MS, LIGHTS_OFF_MS) } builder.setContentTitle(OrgFormatter.parse( @@ -127,7 +131,8 @@ object RemindersNotifications { // Create a group summary notification, but only if notifications can be grouped if (canGroupReminders()) { if (notes.isNotEmpty()) { - val builder = NotificationCompat.Builder(context, NotificationChannels.REMINDERS) + val builder = NotificationCompat.Builder(context, + NotificationChannels.channelIdForReminders()) .setAutoCancel(true) .setSmallIcon(R.drawable.cic_logo_for_notification) .setGroup(Notifications.REMINDERS_GROUP) diff --git a/app/src/main/java/com/orgzly/android/ui/notifications/Notifications.java b/app/src/main/java/com/orgzly/android/ui/notifications/Notifications.java index 6014c4cad..7a530872f 100644 --- a/app/src/main/java/com/orgzly/android/ui/notifications/Notifications.java +++ b/app/src/main/java/com/orgzly/android/ui/notifications/Notifications.java @@ -57,7 +57,7 @@ public static void showOngoingNotification(Context context) { PendingIntent newNotePendingIntent = ShareActivity.createNewNotePendingIntent(context, "ongoing notification", null); - NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationChannels.ONGOING) + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationChannels.channelIdForOngoing()) .setOngoing(true) .setSmallIcon(R.drawable.cic_logo_for_notification) .setContentTitle(context.getString(R.string.new_note)) diff --git a/app/src/main/java/com/orgzly/android/ui/settings/SettingsFragment.kt b/app/src/main/java/com/orgzly/android/ui/settings/SettingsFragment.kt index 57a1333ea..3a40de96b 100644 --- a/app/src/main/java/com/orgzly/android/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/orgzly/android/ui/settings/SettingsFragment.kt @@ -6,6 +6,7 @@ import android.content.SharedPreferences import android.os.Build import android.os.Bundle import android.os.Handler +import android.widget.Toast import androidx.annotation.StringRes import androidx.preference.* import com.orgzly.BuildConfig @@ -26,6 +27,7 @@ import com.orgzly.android.usecase.UseCase import com.orgzly.android.util.AppPermissions import com.orgzly.android.util.LogUtils import com.orgzly.android.widgets.ListWidgetProvider +import com.orgzly.android.NotificationChannels /** * Displays settings. @@ -124,6 +126,18 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP } } + preference(R.string.pref_key_reminders_led_color)?.let { + it.setOnPreferenceChangeListener { + _, newValue -> + val pattern = Regex("^#[0-9A-Fa-f]{6}$") + val stringCorrect = pattern.matches(newValue.toString()) + if (!stringCorrect) { + Toast.makeText(activity, "Please enter a hexadecimal value for color.", Toast.LENGTH_SHORT).show() + } + stringCorrect + } + } + /* Update preferences which depend on multiple others. */ updateRemindersScreen() updateWidgetScreen() @@ -369,6 +383,7 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP updateRemindersScreen() updateWidgetScreen() + updateNotificationChannels() /* Always notify about possibly changed data, if settings are modified. * @@ -381,6 +396,11 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP SharingShortcutsManager().replaceDynamicShortcuts(requireContext()) } + private fun updateNotificationChannels() { + var context = requireContext(); + NotificationChannels.updateAll(context); + } + private fun updateRemindersScreen() { val scheduled = preference(R.string.pref_key_use_reminders_for_scheduled_times) val deadline = preference(R.string.pref_key_use_reminders_for_deadline_times) @@ -403,6 +423,7 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP preference(R.string.pref_key_snooze_time)?.isEnabled = remindersEnabled preference(R.string.pref_key_snooze_type)?.isEnabled = remindersEnabled preference(R.string.pref_key_daily_reminder_time)?.isEnabled = remindersEnabled + preference(R.string.pref_key_reminders_led_color)?.isEnabled = remindersEnabled } } diff --git a/app/src/main/res/values/prefs_keys.xml b/app/src/main/res/values/prefs_keys.xml index 686ef9ad0..4774414c1 100644 --- a/app/src/main/res/values/prefs_keys.xml +++ b/app/src/main/res/values/prefs_keys.xml @@ -259,6 +259,9 @@ pref_key_reminders_led true + + pref_key_reminders_led_color + #0000FF pref_key_daily_reminder_time diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 32016cc3d..6ffdec313 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -490,6 +490,8 @@ Sound Vibration Light + LED color + Set the color of the LED. Has no effect on existing notifications. Snooze time (minutes) Snooze type diff --git a/app/src/main/res/xml/prefs_screen_reminders.xml b/app/src/main/res/xml/prefs_screen_reminders.xml index 8bb70730e..9d7d4557c 100644 --- a/app/src/main/res/xml/prefs_screen_reminders.xml +++ b/app/src/main/res/xml/prefs_screen_reminders.xml @@ -42,7 +42,7 @@ android:key="@string/pref_key_reminders_sound" android:title="@string/pref_title_reminders_sound" android:defaultValue="@bool/pref_default_reminders_sound" /> - + + +