add missing APIs

pull/340/head
Lucas Nogueira 2 years ago
parent 0b29107d71
commit cf47c8ef6d
No known key found for this signature in database
GPG Key ID: FFEA6C72E73482F1

@ -1,3 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> package="app.tauri.notification">
<application>
<receiver android:name="app.tauri.notification.TimedNotificationPublisher" />
<receiver android:name="app.tauri.notification.NotificationDismissReceiver" />
<receiver
android:name="app.tauri.notification.NotificationRestoreReceiver"
android:directBootAware="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
</manifest> </manifest>

@ -30,6 +30,8 @@ class Notification {
var schedule: NotificationSchedule? = null var schedule: NotificationSchedule? = null
var channelId: String? = null var channelId: String? = null
var source: String? = null var source: String? = null
var visibility: Int? = null
var number: Int? = null
fun getSound(context: Context, defaultSound: Int): String? { fun getSound(context: Context, defaultSound: Int): String? {
var soundPath: String? = null var soundPath: String? = null
@ -86,87 +88,6 @@ class Notification {
val isScheduled = schedule != null val isScheduled = schedule != null
override fun toString(): String {
return "Notification{" +
"title='" +
title +
'\'' +
", body='" +
body +
'\'' +
", id=" +
id +
", sound='" +
sound +
'\'' +
", smallIcon='" +
smallIcon +
'\'' +
", iconColor='" +
iconColor +
'\'' +
", actionTypeId='" +
actionTypeId +
'\'' +
", group='" +
group +
'\'' +
", extra=" +
extra +
", attachments=" +
attachments +
", schedule=" +
schedule +
", groupSummary=" +
isGroupSummary +
", ongoing=" +
isOngoing +
", autoCancel=" +
isAutoCancel +
'}'
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
val that = other as Notification
if (if (title != null) title != that.title else that.title != null) return false
if (if (body != null) body != that.body else that.body != null) return false
if (if (largeBody != null) largeBody != that.largeBody else that.largeBody != null) return false
if (id != that.id) return false
if (if (sound != null) sound != that.sound else that.sound != null) return false
if (if (smallIcon != null) smallIcon != that.smallIcon else that.smallIcon != null) return false
if (if (largeIcon != null) largeIcon != that.largeIcon else that.largeIcon != null) return false
if (if (iconColor != null) iconColor != that.iconColor else that.iconColor != null) return false
if (if (actionTypeId != null) actionTypeId != that.actionTypeId else that.actionTypeId != null) return false
if (if (group != null) group != that.group else that.group != null) return false
if (if (extra != null) extra != that.extra else that.extra != null) return false
if (if (attachments != null) attachments != that.attachments else that.attachments != null) return false
if (if (inboxLines != null) inboxLines != that.inboxLines else that.inboxLines != null) return false
if (isGroupSummary != that.isGroupSummary) return false
if (isOngoing != that.isOngoing) return false
if (isAutoCancel != that.isAutoCancel) return false
return if (schedule != null) schedule?.equals(that.schedule) ?: false else that.schedule == null
}
override fun hashCode(): Int {
var result = if (title != null) title.hashCode() else 0
result = 31 * result + if (body != null) body.hashCode() else 0
result = 31 * result + id.hashCode()
result = 31 * result + if (sound != null) sound.hashCode() else 0
result = 31 * result + if (smallIcon != null) smallIcon.hashCode() else 0
result = 31 * result + if (iconColor != null) iconColor.hashCode() else 0
result = 31 * result + if (actionTypeId != null) actionTypeId.hashCode() else 0
result = 31 * result + if (group != null) group.hashCode() else 0
result = 31 * result + java.lang.Boolean.hashCode(isGroupSummary)
result = 31 * result + java.lang.Boolean.hashCode(isOngoing)
result = 31 * result + java.lang.Boolean.hashCode(isAutoCancel)
result = 31 * result + if (extra != null) extra.hashCode() else 0
result = 31 * result + if (attachments != null) attachments.hashCode() else 0
result = 31 * result + if (schedule != null) schedule.hashCode() else 0
return result
}
companion object { companion object {
fun fromJson(jsonNotification: JSONObject): Notification { fun fromJson(jsonNotification: JSONObject): Notification {
val notification: JSObject = try { val notification: JSObject = try {
@ -205,6 +126,8 @@ class Notification {
notification.extra = jsonObject.getJSObject("extra") notification.extra = jsonObject.getJSObject("extra")
notification.isOngoing = jsonObject.getBoolean("ongoing", false) notification.isOngoing = jsonObject.getBoolean("ongoing", false)
notification.isAutoCancel = jsonObject.getBoolean("autoCancel", true) notification.isAutoCancel = jsonObject.getBoolean("autoCancel", true)
notification.visibility = jsonObject.getInteger("visibility")
notification.number = jsonObject.getInteger("number")
try { try {
val inboxLines = jsonObject.getJSONArray("inboxLines") val inboxLines = jsonObject.getJSONArray("inboxLines")
val inboxStringList: MutableList<String> = ArrayList() val inboxStringList: MutableList<String> = ArrayList()

@ -31,7 +31,7 @@ fun getIntervalTime(interval: NotificationInterval, count: Int): Long {
sealed class ScheduleKind { sealed class ScheduleKind {
// At specific moment of time (with repeating option) // At specific moment of time (with repeating option)
class At(val date: Date, val repeating: Boolean): ScheduleKind() class At(var date: Date, val repeating: Boolean): ScheduleKind()
class Interval(val interval: DateMatch): ScheduleKind() class Interval(val interval: DateMatch): ScheduleKind()
class Every(val interval: NotificationInterval, val count: Int): ScheduleKind() class Every(val interval: NotificationInterval, val count: Int): ScheduleKind()
} }

@ -1,6 +1,5 @@
package app.tauri.notification package app.tauri.notification
import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.AlarmManager import android.app.AlarmManager
@ -11,12 +10,12 @@ import android.content.BroadcastReceiver
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.media.AudioAttributes import android.media.AudioAttributes
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import androidx.core.app.ActivityCompat import android.os.Build.VERSION.SDK_INT
import android.os.UserManager
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
@ -38,7 +37,7 @@ const val DEFAULT_PRESS_ACTION = "tap"
class TauriNotificationManager( class TauriNotificationManager(
private val storage: NotificationStorage, private val storage: NotificationStorage,
private val activity: Activity, private val activity: Activity?,
private val context: Context, private val context: Context,
private val config: JSObject private val config: JSObject
) { ) {
@ -140,12 +139,9 @@ class TauriNotificationManager(
// TODO Progressbar support // TODO Progressbar support
// TODO System categories (DO_NOT_DISTURB etc.) // TODO System categories (DO_NOT_DISTURB etc.)
// TODO control visibility by flag Notification.VISIBILITY_PRIVATE
// TODO Group notifications (setGroup, setGroupSummary, setNumber)
// TODO use NotificationCompat.MessagingStyle for latest API // TODO use NotificationCompat.MessagingStyle for latest API
// TODO expandable notification NotificationCompat.MessagingStyle // TODO expandable notification NotificationCompat.MessagingStyle
// TODO media style notification support NotificationCompat.MediaStyle // TODO media style notification support NotificationCompat.MediaStyle
// TODO custom small/large icons
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
private fun buildNotification( private fun buildNotification(
notificationManager: NotificationManagerCompat, notificationManager: NotificationManagerCompat,
@ -198,7 +194,7 @@ class TauriNotificationManager(
mBuilder.setSubText(notification.summary) mBuilder.setSubText(notification.summary)
} }
} }
mBuilder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE) mBuilder.setVisibility(notification.visibility ?: NotificationCompat.VISIBILITY_PRIVATE)
mBuilder.setOnlyAlertOnce(true) mBuilder.setOnlyAlertOnce(true)
mBuilder.setSmallIcon(notification.getSmallIcon(context, getDefaultSmallIcon(context))) mBuilder.setSmallIcon(notification.getSmallIcon(context, getDefaultSmallIcon(context)))
mBuilder.setLargeIcon(notification.getLargeIcon(context)) mBuilder.setLargeIcon(notification.getLargeIcon(context))
@ -221,13 +217,6 @@ class TauriNotificationManager(
// val notificationJson = JSObject(notification.source ?: "") // val notificationJson = JSObject(notification.source ?: "")
} catch (_: JSONException) { } catch (_: JSONException) {
} }
if (ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
return
}
notificationManager.notify(notification.id, buildNotification) notificationManager.notify(notification.id, buildNotification)
} }
} }
@ -297,7 +286,12 @@ class TauriNotificationManager(
} }
private fun buildIntent(notification: Notification, action: String?): Intent { private fun buildIntent(notification: Notification, action: String?): Intent {
val intent = Intent(context, activity.javaClass) val intent = if (activity != null) {
Intent(context, activity.javaClass)
} else {
val packageName = context.packageName
context.packageManager.getLaunchIntentForPackage(packageName)!!
}
intent.action = Intent.ACTION_MAIN intent.action = Intent.ACTION_MAIN
intent.addCategory(Intent.CATEGORY_LAUNCHER) intent.addCategory(Intent.CATEGORY_LAUNCHER)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
@ -537,4 +531,41 @@ class TimedNotificationPublisher : BroadcastReceiver() {
var NOTIFICATION_KEY = "NotificationPublisher.notification" var NOTIFICATION_KEY = "NotificationPublisher.notification"
var CRON_KEY = "NotificationPublisher.cron" var CRON_KEY = "NotificationPublisher.cron"
} }
} }
class LocalNotificationRestoreReceiver : BroadcastReceiver() {
@SuppressLint("ObsoleteSdkInt")
override fun onReceive(context: Context, intent: Intent) {
if (SDK_INT >= Build.VERSION_CODES.N) {
val um = context.getSystemService(
UserManager::class.java
)
if (um == null || !um.isUserUnlocked) return
}
val storage = NotificationStorage(context)
val ids = storage.getSavedNotificationIds()
val notifications = mutableListOf<Notification>()
val updatedNotifications = mutableListOf<Notification>()
for (id in ids) {
val notification = storage.getSavedNotification(id) ?: continue
val schedule = notification.schedule
if (schedule != null && schedule.kind is ScheduleKind.At) {
val at: Date = schedule.kind.date
if (at.before(Date())) {
// modify the scheduled date in order to show notifications that would have been delivered while device was off.
val newDateTime = Date().time + 15 * 1000
schedule.kind.date = Date(newDateTime)
updatedNotifications.add(notification)
}
}
notifications.add(notification)
}
if (updatedNotifications.size > 0) {
storage.appendNotifications(updatedNotifications)
}
// TODO: deserialize configuration
val notificationManager = TauriNotificationManager(storage, null, context, JSObject())
notificationManager.schedule(notifications)
}
}

@ -131,6 +131,14 @@ interface Options {
* Changes the notification presentation to be silent on iOS (no badge, no sound, not listed). * Changes the notification presentation to be silent on iOS (no badge, no sound, not listed).
*/ */
silent?: boolean silent?: boolean
/**
* Notification visibility.
*/
visibility?: Visibility
/**
* Sets the number of items this notification represents on Android.
*/
number?: number
} }
type ScheduleInterval = { type ScheduleInterval = {

Loading…
Cancel
Save