Model ongoing call notifications and independent foreground stop failures
This commit is contained in:
1 parent
a65385bbb1
commit
0a48cccd9a
3 files changed
+42
-4
No files matched your search
+11
-1
@@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
||||
class Notification {
|
||||
companion object { const val VISIBILITY_PUBLIC = 1 }
|
||||
data class Action(val title: String, val intent: PendingIntent)
|
||||
var channelId = ""
|
||||
var title = ""
|
||||
@@ -17,10 +18,14 @@ class Notification {
|
||||
var contentIntent: PendingIntent? = null
|
||||
var fullScreenIntent: PendingIntent? = null
|
||||
var bigText: String? = null
|
||||
var visibility = 0; var foregroundBehavior = 0; var showWhen = false; var chronometer = false; var whenMs = 0L
|
||||
var person: androidx.core.app.Person? = null
|
||||
var hangup: PendingIntent? = null
|
||||
val actions = mutableListOf<Action>()
|
||||
}
|
||||
|
||||
class NotificationChannel(val id: String, val name: String, val importance: Int) {
|
||||
var lockscreenVisibility = 0
|
||||
var description = ""
|
||||
var vibration = true
|
||||
var silent = false
|
||||
@@ -30,7 +35,7 @@ class NotificationChannel(val id: String, val name: String, val importance: Int)
|
||||
|
||||
/** Host OS boundaries: отказы канала, разрешений и публикации независимы. */
|
||||
class NotificationManager {
|
||||
companion object { const val IMPORTANCE_HIGH = 4; const val IMPORTANCE_LOW = 2 }
|
||||
companion object { const val IMPORTANCE_HIGH = 4; const val IMPORTANCE_LOW = 2; const val IMPORTANCE_DEFAULT = 3 }
|
||||
var failures = emptySet<String>()
|
||||
var notificationsEnabled = true
|
||||
var fullScreenAllowed = true
|
||||
@@ -45,6 +50,10 @@ class NotificationManager {
|
||||
check("channel" !in failures) { "channel unavailable" }
|
||||
channels[channel.id] = channel
|
||||
}
|
||||
fun getNotificationChannel(id: String): NotificationChannel? {
|
||||
check("channel query" !in failures) { "channel query unavailable" }
|
||||
return channels[id]
|
||||
}
|
||||
fun canUseFullScreenIntent(): Boolean {
|
||||
fullScreenQueries++
|
||||
check("full screen" !in failures) { "full-screen service unavailable" }
|
||||
@@ -94,6 +103,7 @@ class PendingIntent private constructor(val kind: String, val requestCode: Int,
|
||||
}
|
||||
fun getActivity(context: Context, requestCode: Int, intent: Intent, flags: Int) = obtain("activity", requestCode, intent, flags)
|
||||
fun getBroadcast(context: Context, requestCode: Int, intent: Intent, flags: Int) = obtain("broadcast", requestCode, intent, flags)
|
||||
fun getService(context: Context, requestCode: Int, intent: Intent, flags: Int) = obtain("service", requestCode, intent, flags)
|
||||
}
|
||||
private var intent = Intent(intent)
|
||||
var failCancel = false
|
||||
|
||||
@@ -13,6 +13,9 @@ open class Service : Context() {
|
||||
var failForeground = false
|
||||
var failForegroundAfter = false
|
||||
var stops = 0
|
||||
var foregroundStops = 0
|
||||
var failForegroundStop = false
|
||||
var failStopSelf = false
|
||||
var destroys = 0
|
||||
open fun onCreate() {}
|
||||
open fun onStartCommand(intent: Intent?, flags: Int, startId: Int) = START_NOT_STICKY
|
||||
@@ -25,7 +28,11 @@ open class Service : Context() {
|
||||
requireNotNull(notificationManager).notify(id, notification)
|
||||
check(!failForegroundAfter) { "foreground promotion failed after effect" }
|
||||
}
|
||||
fun stopForeground(flags: Int) { if (flags == STOP_FOREGROUND_REMOVE && foregroundId != 0) notificationManager?.cancel(foregroundId) }
|
||||
fun stopSelf() { stops++ }
|
||||
fun stopSelf(startId: Int) { stops++ }
|
||||
fun stopForeground(flags: Int) {
|
||||
foregroundStops++
|
||||
check(!failForegroundStop) { "foreground removal unavailable" }
|
||||
if (flags == STOP_FOREGROUND_REMOVE && foregroundId != 0) notificationManager?.cancel(foregroundId)
|
||||
}
|
||||
fun stopSelf() { stops++; check(!failStopSelf) { "service stop unavailable" } }
|
||||
fun stopSelf(startId: Int) { stopSelf() }
|
||||
}
|
||||
+21
@@ -8,11 +8,16 @@ import android.content.Context
|
||||
object NotificationCompat {
|
||||
const val CATEGORY_CALL = "call"
|
||||
const val PRIORITY_MAX = 2
|
||||
const val VISIBILITY_PUBLIC = 1
|
||||
const val FOREGROUND_SERVICE_IMMEDIATE = 1
|
||||
var failBuild = false
|
||||
class BigTextStyle {
|
||||
var text = ""
|
||||
fun bigText(value: String) = apply { text = value }
|
||||
}
|
||||
class CallStyle(val person: Person, val hangup: PendingIntent) {
|
||||
companion object { fun forOngoingCall(person: Person, hangup: PendingIntent) = CallStyle(person, hangup) }
|
||||
}
|
||||
class Builder(context: Context, channelId: String) {
|
||||
private val notification = Notification().apply { this.channelId = channelId }
|
||||
fun setSmallIcon(value: Int) = this
|
||||
@@ -26,11 +31,27 @@ object NotificationCompat {
|
||||
fun setContentIntent(value: PendingIntent) = apply { notification.contentIntent = value }
|
||||
fun setFullScreenIntent(value: PendingIntent, priority: Boolean) = apply { check(priority); notification.fullScreenIntent = value }
|
||||
fun setStyle(value: BigTextStyle) = apply { notification.bigText = value.text }
|
||||
fun setStyle(value: CallStyle) = apply { notification.person = value.person; notification.hangup = value.hangup }
|
||||
fun setVisibility(value: Int) = apply { notification.visibility = value }
|
||||
fun setForegroundServiceBehavior(value: Int) = apply { notification.foregroundBehavior = value }
|
||||
fun addPerson(value: Person) = this
|
||||
fun setShowWhen(value: Boolean) = apply { notification.showWhen = value }
|
||||
fun setUsesChronometer(value: Boolean) = apply { notification.chronometer = value }
|
||||
fun setWhen(value: Long) = apply { notification.whenMs = value }
|
||||
fun addAction(icon: Int, title: String, intent: PendingIntent) = apply { notification.actions.add(Notification.Action(title, intent)) }
|
||||
fun build(): Notification { check(!failBuild) { "notification build unavailable" }; return notification }
|
||||
}
|
||||
}
|
||||
|
||||
class Person private constructor(val name: String, val key: String) {
|
||||
class Builder {
|
||||
private var name = ""; private var key = ""
|
||||
fun setName(value: String) = apply { name = value }
|
||||
fun setKey(value: String) = apply { key = value }
|
||||
fun build() = Person(name, key)
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationManagerCompat private constructor(private val context: Context) {
|
||||
companion object { fun from(context: Context) = NotificationManagerCompat(context) }
|
||||
private val manager get() = requireNotNull(context.notificationManager) { "notification manager unavailable" }
|
||||
|
||||
Reference in new issue
Block a user