1
1
package com.sanmer.mrepo.service
2
2
3
3
import android.Manifest
4
+ import android.annotation.SuppressLint
4
5
import android.app.Notification
5
6
import android.content.Context
6
7
import android.content.Intent
7
- import android.content.pm.PackageManager
8
8
import android.os.Build
9
9
import android.os.Parcel
10
10
import android.os.Parcelable
11
11
import androidx.core.app.NotificationCompat
12
12
import androidx.core.app.NotificationManagerCompat
13
13
import androidx.core.app.ServiceCompat
14
- import androidx.core.content.ContextCompat
15
14
import androidx.documentfile.provider.DocumentFile
16
15
import androidx.lifecycle.LifecycleService
17
16
import androidx.lifecycle.lifecycleScope
@@ -43,11 +42,11 @@ import javax.inject.Inject
43
42
44
43
@AndroidEntryPoint
45
44
class DownloadService : LifecycleService () {
45
+ @Inject lateinit var userPreferencesRepository: UserPreferencesRepository
46
+
46
47
private val context: Context by lazy { applicationContext }
47
48
private val tasks = mutableListOf<TaskItem >()
48
49
49
- @Inject lateinit var userPreferencesRepository: UserPreferencesRepository
50
-
51
50
init {
52
51
lifecycleScope.launch {
53
52
while (isActive) {
@@ -61,7 +60,7 @@ class DownloadService : LifecycleService() {
61
60
.flowOn(Dispatchers .IO )
62
61
.onEach { (item, progress) ->
63
62
if (progress != 0f ) {
64
- notifyProgress (item, progress)
63
+ onProgressChanged (item, progress)
65
64
}
66
65
}
67
66
.launchIn(lifecycleScope)
@@ -70,9 +69,17 @@ class DownloadService : LifecycleService() {
70
69
override fun onCreate () {
71
70
Timber .d(" DownloadService onCreate" )
72
71
super .onCreate()
72
+
73
73
setForeground()
74
74
}
75
75
76
+ override fun onDestroy () {
77
+ ServiceCompat .stopForeground(this , ServiceCompat .STOP_FOREGROUND_DETACH )
78
+
79
+ Timber .d(" DownloadService onDestroy" )
80
+ super .onDestroy()
81
+ }
82
+
76
83
override fun onStartCommand (intent : Intent ? , flags : Int , startId : Int ): Int {
77
84
lifecycleScope.launch {
78
85
val item = intent?.taskItemOrNull ? : return @launch
@@ -85,7 +92,7 @@ class DownloadService : LifecycleService() {
85
92
86
93
val df = downloadPath.createFile(" */*" , item.filename)
87
94
if (df == null ) {
88
- notifyFailure (item, " Failed to create file" )
95
+ onDownloadFailed (item, " Failed to create file" )
89
96
return @launch
90
97
}
91
98
@@ -94,7 +101,7 @@ class DownloadService : LifecycleService() {
94
101
contentResolver.openOutputStream(df.uri)
95
102
)
96
103
} catch (e: FileNotFoundException ) {
97
- notifyFailure (item, e.message)
104
+ onDownloadFailed (item, e.message)
98
105
return @launch
99
106
}
100
107
@@ -105,15 +112,15 @@ class DownloadService : LifecycleService() {
105
112
}
106
113
107
114
override fun onSuccess () {
108
- notifySuccess (item)
115
+ onDownloadSucceeded (item)
109
116
110
117
progressFlow.value = item to 0f
111
118
listeners[item]?.onSuccess()
112
119
tasks.remove(item)
113
120
}
114
121
115
122
override fun onFailure (e : Throwable ) {
116
- notifyFailure (item, e.message)
123
+ onDownloadFailed (item, e.message)
117
124
118
125
progressFlow.value = item to 0f
119
126
listeners[item]?.onFailure(e)
@@ -137,12 +144,6 @@ class DownloadService : LifecycleService() {
137
144
return super .onStartCommand(intent, flags, startId)
138
145
}
139
146
140
- override fun onDestroy () {
141
- Timber .d(" DownloadService onDestroy" )
142
- ServiceCompat .stopForeground(this , ServiceCompat .STOP_FOREGROUND_REMOVE )
143
- super .onDestroy()
144
- }
145
-
146
147
private fun setForeground () {
147
148
val notification = NotificationCompat .Builder (this , NotificationUtils .CHANNEL_ID_DOWNLOAD )
148
149
.setSmallIcon(R .drawable.launcher_outline)
@@ -156,31 +157,7 @@ class DownloadService : LifecycleService() {
156
157
startForeground(NotificationUtils .NOTIFICATION_ID_DOWNLOAD , notification)
157
158
}
158
159
159
- private fun buildNotification (
160
- title : String? ,
161
- desc : String? ,
162
- silent : Boolean = false,
163
- ongoing : Boolean = false,
164
- ) = NotificationCompat .Builder (context, NotificationUtils .CHANNEL_ID_DOWNLOAD )
165
- .setSmallIcon(R .drawable.launcher_outline)
166
- .setContentTitle(title)
167
- .setSubText(desc)
168
- .setSilent(silent)
169
- .setOngoing(ongoing)
170
- .setGroup(GROUP_KEY )
171
-
172
- private fun notify (id : Int , notification : Notification ) {
173
- val notificationId = NotificationUtils .NOTIFICATION_ID_DOWNLOAD + id
174
- NotificationManagerCompat .from(context).apply {
175
- if (ContextCompat .checkSelfPermission(context, Manifest .permission.POST_NOTIFICATIONS )
176
- != PackageManager .PERMISSION_GRANTED
177
- ) return
178
-
179
- notify(notificationId, notification)
180
- }
181
- }
182
-
183
- private fun notifyProgress (item : TaskItem , progress : Float ) {
160
+ private fun onProgressChanged (item : TaskItem , progress : Float ) {
184
161
val notification = buildNotification(
185
162
title = item.title,
186
163
desc = item.desc,
@@ -193,7 +170,7 @@ class DownloadService : LifecycleService() {
193
170
notify(item.taskId, notification.build())
194
171
}
195
172
196
- private fun notifySuccess (item : TaskItem ) {
173
+ private fun onDownloadSucceeded (item : TaskItem ) {
197
174
val message = context.getString(R .string.message_download_success)
198
175
val notification = buildNotification(
199
176
title = item.title,
@@ -206,7 +183,7 @@ class DownloadService : LifecycleService() {
206
183
notify(item.taskId, notification.build())
207
184
}
208
185
209
- private fun notifyFailure (item : TaskItem , message : String? ) {
186
+ private fun onDownloadFailed (item : TaskItem , message : String? ) {
210
187
val msg = message ? : context.getString(R .string.unknown_error)
211
188
val notification = buildNotification(
212
189
title = item.title,
@@ -219,6 +196,36 @@ class DownloadService : LifecycleService() {
219
196
notify(item.taskId, notification.build())
220
197
}
221
198
199
+ private fun buildNotification (
200
+ title : String? ,
201
+ desc : String? ,
202
+ silent : Boolean = false,
203
+ ongoing : Boolean = false,
204
+ ) = NotificationCompat .Builder (context, NotificationUtils .CHANNEL_ID_DOWNLOAD )
205
+ .setSmallIcon(R .drawable.launcher_outline)
206
+ .setContentTitle(title)
207
+ .setSubText(desc)
208
+ .setSilent(silent)
209
+ .setOngoing(ongoing)
210
+ .setGroup(GROUP_KEY )
211
+
212
+
213
+ @SuppressLint(" MissingPermission" )
214
+ private fun notify (id : Int , notification : Notification ) {
215
+ val granted = if (BuildCompat .atLeastT) {
216
+ PermissionCompat .checkPermissions(
217
+ context,
218
+ listOf (Manifest .permission.POST_NOTIFICATIONS )
219
+ ).allGranted
220
+ } else {
221
+ true
222
+ }
223
+
224
+ NotificationManagerCompat .from(this ).apply {
225
+ if (granted) notify(id, notification)
226
+ }
227
+ }
228
+
222
229
data class TaskItem (
223
230
val key : String ,
224
231
val url : String ,
0 commit comments