1 /* 2 * Copyright (C) 2020 The LineageOS Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.deskclock 18 19 import android.app.NotificationChannel 20 import android.content.Context 21 import android.util.ArraySet 22 import android.util.Log 23 import androidx.core.app.NotificationManagerCompat 24 import androidx.core.app.NotificationManagerCompat.IMPORTANCE_HIGH 25 import androidx.core.app.NotificationManagerCompat.IMPORTANCE_LOW 26 27 object NotificationUtils { 28 private val TAG = NotificationUtils::class.java.simpleName 29 30 /** 31 * Notification channel containing all missed alarm notifications. 32 */ 33 const val ALARM_MISSED_NOTIFICATION_CHANNEL_ID = "alarmMissedNotification" 34 35 /** 36 * Notification channel containing all upcoming alarm notifications. 37 */ 38 const val ALARM_UPCOMING_NOTIFICATION_CHANNEL_ID = "alarmUpcomingNotification" 39 40 /** 41 * Notification channel containing all snooze notifications. 42 */ 43 const val ALARM_SNOOZE_NOTIFICATION_CHANNEL_ID = "alarmSnoozingNotification" 44 45 /** 46 * Notification channel containing all firing alarm and timer notifications. 47 */ 48 const val FIRING_NOTIFICATION_CHANNEL_ID = "firingAlarmsAndTimersNotification" 49 50 /** 51 * Notification channel containing all TimerModel notifications. 52 */ 53 const val TIMER_MODEL_NOTIFICATION_CHANNEL_ID = "timerNotification" 54 55 /** 56 * Notification channel containing all stopwatch notifications. 57 */ 58 const val STOPWATCH_NOTIFICATION_CHANNEL_ID = "stopwatchNotification" 59 60 /** 61 * Values used to bitmask certain channel defaults 62 */ 63 private const val PLAY_SOUND = 0x01 64 private const val ENABLE_LIGHTS = 0x02 65 private const val ENABLE_VIBRATION = 0x04 66 67 private val CHANNEL_PROPS: MutableMap<String, IntArray> = HashMap() 68 69 init { 70 CHANNEL_PROPS[ALARM_MISSED_NOTIFICATION_CHANNEL_ID] = intArrayOf( 71 R.string.alarm_missed_channel, 72 IMPORTANCE_HIGH 73 ) 74 CHANNEL_PROPS[ALARM_SNOOZE_NOTIFICATION_CHANNEL_ID] = intArrayOf( 75 R.string.alarm_snooze_channel, 76 IMPORTANCE_LOW 77 ) 78 CHANNEL_PROPS[ALARM_UPCOMING_NOTIFICATION_CHANNEL_ID] = intArrayOf( 79 R.string.alarm_upcoming_channel, 80 IMPORTANCE_LOW 81 ) 82 CHANNEL_PROPS[FIRING_NOTIFICATION_CHANNEL_ID] = intArrayOf( 83 R.string.firing_alarms_timers_channel, 84 IMPORTANCE_HIGH, 85 ENABLE_LIGHTS 86 ) 87 CHANNEL_PROPS[STOPWATCH_NOTIFICATION_CHANNEL_ID] = intArrayOf( 88 R.string.stopwatch_channel, 89 IMPORTANCE_LOW 90 ) 91 CHANNEL_PROPS[TIMER_MODEL_NOTIFICATION_CHANNEL_ID] = intArrayOf( 92 R.string.timer_channel, 93 IMPORTANCE_LOW 94 ) 95 } 96 97 @JvmStatic createChannelnull98 fun createChannel(context: Context, id: String) { 99 if (!Utils.isOOrLater) { 100 return 101 } 102 103 if (!CHANNEL_PROPS.containsKey(id)) { 104 Log.e(TAG, "Invalid channel requested: $id") 105 return 106 } 107 108 val properties = CHANNEL_PROPS[id]!! 109 val nameId = properties[0] 110 val importance = properties[1] 111 val channel = NotificationChannel(id, context.getString(nameId), importance) 112 if (properties.size >= 3) { 113 val bits = properties[2] 114 channel.enableLights(bits and ENABLE_LIGHTS != 0) 115 channel.enableVibration(bits and ENABLE_VIBRATION != 0) 116 if (bits and PLAY_SOUND == 0) { 117 channel.setSound(null, null) 118 } 119 } 120 val nm: NotificationManagerCompat = NotificationManagerCompat.from(context) 121 nm.createNotificationChannel(channel) 122 } 123 deleteChannelnull124 private fun deleteChannel(nm: NotificationManagerCompat, channelId: String) { 125 val channel: NotificationChannel? = nm.getNotificationChannel(channelId) 126 if (channel != null) { 127 nm.deleteNotificationChannel(channelId) 128 } 129 } 130 getAllExistingChannelIdsnull131 private fun getAllExistingChannelIds(nm: NotificationManagerCompat): Set<String> { 132 val result: MutableSet<String> = ArraySet() 133 for (channel in nm.getNotificationChannels()) { 134 result.add(channel.id) 135 } 136 return result 137 } 138 139 @JvmStatic updateNotificationChannelsnull140 fun updateNotificationChannels(context: Context) { 141 if (!Utils.isOOrLater) { 142 return 143 } 144 145 val nm: NotificationManagerCompat = NotificationManagerCompat.from(context) 146 147 // These channels got a new behavior so we need to recreate them with new ids 148 deleteChannel(nm, "alarmLowPriorityNotification") 149 deleteChannel(nm, "alarmHighPriorityNotification") 150 deleteChannel(nm, "StopwatchNotification") 151 deleteChannel(nm, "alarmNotification") 152 deleteChannel(nm, "TimerModelNotification") 153 deleteChannel(nm, "alarmSnoozeNotification") 154 155 // We recreate all existing channels so any language change or our name changes propagate 156 // to the actual channels 157 val existingChannelIds = getAllExistingChannelIds(nm) 158 for (id in existingChannelIds) { 159 createChannel(context, id) 160 } 161 } 162 }