From 4c0ba22041ac01a5f0e1cc88a6c292034d697955 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Mon, 9 Apr 2018 01:17:21 -0400 Subject: Feature/download manager (#855) * Add initial github release check * Create update service * Clean old manager directory * Update kau * Update updateActivity snippet * Add back gradle keys * Remove update service functionality --- .../frost/services/NotificationUtils.kt | 147 +++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt (limited to 'app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt') diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt new file mode 100644 index 00000000..7014cb78 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt @@ -0,0 +1,147 @@ +package com.pitchedapps.frost.services + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.job.JobInfo +import android.app.job.JobScheduler +import android.app.job.JobService +import android.content.ComponentName +import android.content.Context +import android.net.Uri +import android.os.Build +import android.os.PersistableBundle +import android.support.annotation.RequiresApi +import android.support.v4.app.NotificationCompat +import ca.allanwang.kau.utils.color +import ca.allanwang.kau.utils.string +import com.pitchedapps.frost.R +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs + +/** + * Created by Allan Wang on 07/04/18. + */ +const val NOTIF_CHANNEL_GENERAL = "general" +const val NOTIF_CHANNEL_MESSAGES = "messages" +const val NOTIF_CHANNEL_UPDATES = "updates" + +fun setupNotificationChannels(c: Context) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return + val manager = c.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val appName = c.string(R.string.frost_name) + val msg = c.string(R.string.messages) + val updates = c.string(R.string.updates) + manager.notificationChannels + .filter { + it.id != NOTIF_CHANNEL_GENERAL + && it.id != NOTIF_CHANNEL_MESSAGES + && it.id != NOTIF_CHANNEL_UPDATES + } + .forEach { manager.deleteNotificationChannel(it.id) } + manager.createNotificationChannel(NOTIF_CHANNEL_GENERAL, appName) + manager.createNotificationChannel(NOTIF_CHANNEL_MESSAGES, "$appName: $msg") + manager.createNotificationChannel(NOTIF_CHANNEL_UPDATES, "$appName: $updates") + L.d { "Created notification channels: ${manager.notificationChannels.size} channels, ${manager.notificationChannelGroups.size} groups" } +} + +@RequiresApi(Build.VERSION_CODES.O) +private fun NotificationManager.createNotificationChannel(id: String, name: String): NotificationChannel { + val channel = NotificationChannel(id, + name, NotificationManager.IMPORTANCE_DEFAULT) + channel.enableLights(true) + channel.lightColor = Prefs.accentColor + channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC + createNotificationChannel(channel) + return channel +} + +fun Context.frostNotification(id: String) = + NotificationCompat.Builder(this, id) + .apply { + setSmallIcon(R.drawable.frost_f_24) + setAutoCancel(true) + setOnlyAlertOnce(true) + setStyle(NotificationCompat.BigTextStyle()) + color = color(R.color.frost_notification_accent) + } + +/** + * Dictates whether a notification should have sound/vibration/lights or not + * Delegates to channels if Android O and up + * Otherwise uses our provided preferences + */ +fun NotificationCompat.Builder.setFrostAlert(enable: Boolean, ringtone: String): NotificationCompat.Builder { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setGroupAlertBehavior( + if (enable) Notification.GROUP_ALERT_CHILDREN + else Notification.GROUP_ALERT_SUMMARY) + } else if (!enable) { + setDefaults(0) + } else { + var defaults = 0 + if (Prefs.notificationVibrate) defaults = defaults or Notification.DEFAULT_VIBRATE + if (Prefs.notificationSound) { + if (ringtone.isNotBlank()) setSound(Uri.parse(ringtone)) + else defaults = defaults or Notification.DEFAULT_SOUND + } + if (Prefs.notificationLights) defaults = defaults or Notification.DEFAULT_LIGHTS + setDefaults(defaults) + } + return this +} + +/* + * ----------------------------------- + * Job Scheduler + * ----------------------------------- + */ + +const val NOTIFICATION_PARAM_ID = "notif_param_id" + +fun JobInfo.Builder.setExtras(id: Int): JobInfo.Builder { + val bundle = PersistableBundle() + bundle.putInt(NOTIFICATION_PARAM_ID, id) + return setExtras(bundle) +} + +/** + * interval is # of min, which must be at least 15 + * returns false if an error occurs; true otherwise + */ +inline fun Context.scheduleJob(id: Int, minutes: Long): Boolean { + val scheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler + scheduler.cancel(id) + if (minutes < 0L) return true + val serviceComponent = ComponentName(this, T::class.java) + val builder = JobInfo.Builder(id, serviceComponent) + .setPeriodic(minutes * 60000) + .setExtras(id) + .setPersisted(true) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) //TODO add options + val result = scheduler.schedule(builder.build()) + if (result <= 0) { + L.eThrow("${T::class.java.simpleName} scheduler failed") + return false + } + return true +} + +/** + * Run notification job right now + */ +inline fun Context.fetchJob(id: Int): Boolean { + val scheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler + val serviceComponent = ComponentName(this, T::class.java) + val builder = JobInfo.Builder(id, serviceComponent) + .setMinimumLatency(0L) + .setExtras(id) + .setOverrideDeadline(2000L) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + val result = scheduler.schedule(builder.build()) + if (result <= 0) { + L.eThrow("${T::class.java.simpleName} instant scheduler failed") + return false + } + return true +} \ No newline at end of file -- cgit v1.2.3