-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathIPv8Service.kt
170 lines (146 loc) · 5.26 KB
/
IPv8Service.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package nl.tudelft.ipv8.android.service
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.Service
import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.content.getSystemService
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import kotlinx.coroutines.*
import nl.tudelft.ipv8.*
import nl.tudelft.ipv8.android.IPv8Android
import nl.tudelft.ipv8.android.R
import kotlin.system.exitProcess
open class IPv8Service : Service(), LifecycleObserver {
protected val scope = CoroutineScope(Dispatchers.Default)
private var isForeground = false
override fun onCreate() {
super.onCreate()
createNotificationChannel()
showForegroundNotification()
ProcessLifecycleOwner.get()
.lifecycle
.addObserver(this)
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onDestroy() {
getIPv8().stop()
scope.cancel()
ProcessLifecycleOwner.get()
.lifecycle
.removeObserver(this)
super.onDestroy()
// We need to kill the app as IPv8 is started in Application.onCreate
exitProcess(0)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onBackground() {
isForeground = false
updateNotification()
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onForeground() {
isForeground = true
updateNotification()
}
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_LOW
val channel =
NotificationChannel(
NOTIFICATION_CHANNEL_CONNECTION,
getString(R.string.notification_channel_connection_title),
importance,
)
channel.description = getString(R.string.notification_channel_connection_description)
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
val notificationManager = getSystemService<NotificationManager>()
notificationManager?.createNotificationChannel(channel)
}
}
private fun showForegroundNotification() {
val builder = createNotification()
// Allow cancellation when the app is running in background.
// Should technically not be triggered.
if (!isForeground) {
addStopAction(builder)
}
if (SDK_INT > Build.VERSION_CODES.TIRAMISU) {
startForeground(
ONGOING_NOTIFICATION_ID,
builder.build(),
FOREGROUND_SERVICE_TYPE_DATA_SYNC,
)
} else {
startForeground(
ONGOING_NOTIFICATION_ID,
builder.build(),
)
}
}
/**
* Creates a notification that will be shown when the IPv8 service is running.
*/
protected open fun createNotification(): NotificationCompat.Builder {
return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_CONNECTION)
.setContentTitle("IPv8")
.setContentText("Running")
}
/**
* Updates the notification to show the current state of the IPv8 service.
*/
protected fun updateNotification() {
val builder = createNotification()
// Allow cancellation when the app is running in background.
if (!isForeground) {
addStopAction(builder)
}
val mNotificationManager =
getSystemService<NotificationManager>()
mNotificationManager?.notify(ONGOING_NOTIFICATION_ID, builder.build())
}
/**
* Adds a stop action to the notification.
*/
private fun addStopAction(builder: NotificationCompat.Builder) {
val cancelBroadcastIntent = Intent(this, StopIPv8Receiver::class.java)
val flags =
when {
SDK_INT >= Build.VERSION_CODES.M -> FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
else -> FLAG_UPDATE_CURRENT
}
val cancelPendingIntent =
PendingIntent.getBroadcast(
applicationContext,
0,
cancelBroadcastIntent,
flags,
)
builder.addAction(NotificationCompat.Action(0, "Stop", cancelPendingIntent))
}
/**
* Returns a running IPv8 instance.
*/
private fun getIPv8(): IPv8 {
return IPv8Android.getInstance()
}
companion object {
const val NOTIFICATION_CHANNEL_CONNECTION = "service_notifications"
private const val ONGOING_NOTIFICATION_ID = 1
}
}