· 4 years ago · Aug 23, 2021, 02:54 PM
1package com.itsoft.lan.irbis.service
2
3import android.app.Service
4import android.content.Context
5import android.content.Intent
6import android.os.IBinder
7import android.util.Log
8import com.itsoft.lan.irbis.IrbisManager
9import com.itsoft.lan.irbis.R
10import com.itsoft.lan.irbis.data.managers.DataManager
11import com.itsoft.lan.irbis.data.network.RestService
12import com.itsoft.lan.irbis.data.network.RestServices
13import com.itsoft.lan.irbis.data.sendDownloadMessageService.MessageServiceRepository
14import com.itsoft.lan.irbis.di.ServiceAnnotation
15import com.itsoft.lan.irbis.extensions.checkIsActive
16import com.itsoft.lan.irbis.extensions.clearAllDisposable
17import com.itsoft.lan.irbis.model.Message
18import com.itsoft.lan.irbis.model.Publication.DataItem
19import com.itsoft.lan.irbis.utils.LogUtils
20import com.itsoft.lan.irbis.utils.LogUtils.Companion.log
21import com.itsoft.lan.irbis.utils.NetworkHelper
22import com.itsoft.lan.irbis.utils.TimerHelper
23import com.itsoft.lan.irbis.utils.TimerHelper.TimerListener
24import dagger.hilt.android.AndroidEntryPoint
25import io.reactivex.observers.DisposableObserver
26import kotlinx.coroutines.*
27import kotlinx.coroutines.flow.catch
28import kotlinx.coroutines.flow.collect
29import java.io.File
30import java.util.*
31import java.util.concurrent.ConcurrentHashMap
32import javax.inject.Inject
33import kotlin.collections.ArrayDeque
34
35@AndroidEntryPoint
36class SendDownloadMessageService : Service() {
37
38 @Inject
39 @ServiceAnnotation
40 lateinit var repository: MessageServiceRepository
41
42 @Inject
43 lateinit var restService: RestService
44
45 @Inject
46 @ServiceAnnotation
47 lateinit var dataManager: DataManager
48
49 private val STOP_SERVICE_TAG: String = "StopService"
50 private val SEND_DOWNLOAD_MESSAGE_TAG: String = "SendDownloadMessageService"
51 private val PUBLISH_ERROR_TAG: String = "PublishMessageErrorTag"
52
53 private val uploadMap: MutableMap<Int, Job> = hashMapOf()
54 private val downloadMap: MutableMap<Int, Job> = hashMapOf()
55 private val downloadFileMap: MutableMap<String, Job> = hashMapOf()
56
57 private val errorTimerMap: MutableMap<Int, TimerHelper> = hashMapOf()
58
59 private var callSocket = true
60 private var wasScheduled = false
61 private var baseURL: String? = null
62 private var errorTimer: TimerHelper? = null
63
64 //Очередь сообщений
65 private val messageQueue = ArrayDeque<Message>()
66 private val messagesToSend: MutableMap<Date, Message> = ConcurrentHashMap()
67
68 //Интервал работы таймера
69 private val timerInterval: Int = 80000
70
71 override fun onCreate() {
72 super.onCreate()
73 baseURL = repository.getBaseUrl()
74 }
75
76 override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
77 when (intent.getStringExtra(ACTION)) {
78 ACTION_START_STOP_DOWNLOAD -> {
79 intent.getParcelableExtra<Message>(MESSAGE)?.let { message ->
80 log(message = "onStartCommand Action Download message data ${message.localId}")
81 message.unPackData(message.dataType)
82 download(message)
83 }
84 }
85 ACTION_STOP_UPLOAD -> {
86 intent.getParcelableExtra<Message>(MESSAGE)?.let { message ->
87 log(message = "onStartCommand Action Stop upload data for message ${message.localId}")
88 message.unPackData(message.dataType)
89 stopUpload(message)
90 }
91 }
92 ACTION_START_STOP_UPLOAD -> {
93 intent.getParcelableExtra<Message>(MESSAGE)?.let { message ->
94 log(message = "onStartCommand Action Start strop upload data ${message.localId}")
95 message.unPackData(message.dataType)
96 upload(message)
97 }
98 }
99 ACTION_START_SEND_MESSAGE -> {
100 intent.getParcelableExtra<Message>(MESSAGE)?.let { message ->
101 log(message = "onStartCommand Action Start send message ${message.localId}")
102 message.unPackData(message.dataType)
103 sendMessage(message)
104 }
105 }
106 ACTION_START_STOP_DOWNLOAD_PUBLICATION -> {
107 intent.getParcelableExtra<DataItem>(DATA_ITEM)?.let { item ->
108 log(message = "onStartCommand Action download publication")
109 val pubId = intent.getIntExtra(PUB_ID, -1)
110 val chId = intent.getIntExtra(CH_ID, -1)
111 downloadPublicationFile(item, pubId, chId)
112 }
113 }
114 }
115 return super.onStartCommand(intent, flags, startId)
116 }
117
118 private fun downloadPublicationFile(item: DataItem, pubId: Int, chId: Int) {
119 log(message = "DownloadPublicationFile $pubId $chId")
120 //Получение данных о публикации
121 val file: String = repository.getFile(item) ?: return
122 val key: String? = repository.getKey(item)
123 val extension: String = repository.getExtension(item) ?: return
124
125 //Проверка, что вложение уже существует.
126 downloadFileMap[file]?.let {
127 it.cancel()
128 downloadFileMap.remove(file)
129 hideDownloadPublicationProgressBar(chId, pubId, file, false)
130 return
131 }
132
133 //Устанавливаем начальную загрузку
134 publishPercentPublication(chId, pubId, file, 0)
135
136 //Создаем rest service с отображением процента загрузки
137 val restService = RestServices.createDownloadRestService(baseURL) { bytesRead: Long, contentLength: Long, done: Boolean ->
138 repository.getPublicationDownloadingPercentage(done, item, bytesRead) {
139 publishPercentPublication(chId, pubId, file, it)
140 }
141 }
142
143 //Создаем Job для загрузки вложения
144 val job: Job = CoroutineScope(Dispatchers.IO).launch {
145 dataManager.downloadPublicationMedia(
146 file,
147 key,
148 extension,
149 restService
150 ).catch {
151 log(message = it.message ?: getString(R.string.unknown_error))
152 publishErrorPublication(chId, pubId, file)
153 stopService()
154 }.collect {
155 log(message = "DownloadPublicationFile $pubId $chId")
156 hideDownloadPublicationProgressBar(chId, pubId, file, true)
157 downloadFileMap[file]?.let {
158 downloadFileMap.remove(file)
159 it.cancel()
160 }
161 stopService()
162 }
163 }
164
165
166 log(message = "Set job for publication $pubId on channel $chId")
167 downloadFileMap[file] = job
168 }
169
170 /**
171 * Рассылает сигнал [ACTION_HIDE_DOWNLOAD_PUBLICATION_PROGRESS_BAR] через broadcast
172 * @param chId ID канала
173 * @param pubId ID публикации
174 * @param file имя файла [String], который загружается
175 * @param done статус [Boolean] завершения загрузки
176 */
177 private fun hideDownloadPublicationProgressBar(
178 chId: Int,
179 pubId: Int,
180 file: String,
181 done: Boolean
182 ) {
183 log(message = "Hide download progress bar for publication $pubId on channel $chId")
184 sendBroadcast(Intent(NOTIFICATION).apply {
185 putExtra(ACTION, ACTION_HIDE_DOWNLOAD_PUBLICATION_PROGRESS_BAR)
186 putExtra(PUB_ID, pubId)
187 putExtra(CH_ID, chId)
188 putExtra(FILE, file)
189 putExtra(DONE, done)
190 })
191 }
192
193 /**
194 * Рассылает сигнал [ACTION_PUBLISH_PUBLICATION_PERCENT] через broadcast
195 * @param chId ID канала
196 * @param pubId ID публикации
197 * @param file имя файла [String], который загружается
198 * @param percent количество процентов от 1 до 100. Показывает степерь загрузки
199 */
200 private fun publishPercentPublication(
201 chId: Int,
202 pubId: Int,
203 file: String,
204 percent: Int
205 ) {
206 log(message = "publish publication download percent $percent, publication $pubId on channel $chId")
207 sendBroadcast(Intent(NOTIFICATION).apply {
208 putExtra(ACTION, ACTION_PUBLISH_PUBLICATION_PERCENT)
209 putExtra(PUB_ID, pubId)
210 putExtra(CH_ID, chId)
211 putExtra(FILE, file)
212 putExtra(PERCENT, percent)
213 })
214 }
215
216 /**
217 * Рассылает сигнал [ACTION_PUBLISH_PUBLICATION_ERROR] через broadcast
218 * @param chId ID канала.
219 * @param pubId ID публикации.
220 * @param file имя файла [String], при загрузке которого произошла ошибка.
221 */
222 private fun publishErrorPublication(
223 chId: Int,
224 pubId: Int,
225 file: String
226 ) {
227 log(message = "publish download error, publication $pubId on channel $chId")
228 sendBroadcast(Intent(NOTIFICATION).apply {
229 putExtra(ACTION, ACTION_PUBLISH_PUBLICATION_ERROR)
230 putExtra(PUB_ID, pubId)
231 putExtra(CH_ID, chId)
232 putExtra(FILE, file)
233 })
234 }
235
236 override fun onBind(intent: Intent): IBinder? {
237 return null
238 }
239
240 /**
241 * Добавляет сообщение в очередь сообщений
242 * @param message объект [Message]
243 */
244 private fun sendMessageQueue(message: Message) {
245 log(message = "Send message queue for message ${message.localId}")
246 messageQueue.add(message)
247 if (callSocket) {
248 callSocket = false
249 sendMessageSocket()
250 }
251 }
252
253 /**
254 * Оповещает, если не удалось отправить сообщение.
255 */
256 private fun setErrorMessage(message: Message) {
257 log(Log.DEBUG, SERVICE_TAG/*PUBLISH_ERROR_TAG*/, "publishError ${message.localId}")
258 IrbisManager.storage().setSendingMessageStatus(message.localId, Message.STATUS_ERROR)
259 repository.publishError(message)
260 }
261
262 /**
263 * Отправка сообщения
264 */
265 private fun sendMessage(message: Message) {
266 //Проверка наличия сети
267 checkInternetAndInitWorker { isConnected ->
268 //Если нет соединения, вернуться
269 if (!isConnected) {
270 return@sendMessage
271 }
272 }
273
274 checkMessageDataTypeAndSend(message)
275 }
276
277 /**
278 * Проверяет [Message.dataType] перед отправкой сообщения
279 */
280 private fun checkMessageDataTypeAndSend(message: Message) {
281 //Если dataType IMAGE, VIDEO, FILE, AUDIO, проверить наличие файла для отправки.
282 //Иначе добавить сообщение в очередь сообщений.
283 when (message.dataType) {
284 Message.IMAGE_MESSAGE -> {
285 sendOrUploadMessage(message, message.asImageData().file)
286 }
287 Message.VIDEO_MESSAGE -> {
288 sendOrUploadMessage(message, message.asVideoData().file)
289 }
290 Message.FILE_MESSAGE -> {
291 sendOrUploadMessage(message, message.asFileData().file)
292 }
293 Message.AUDIO_MESSAGE -> {
294 sendOrUploadMessage(message, message.asAudioData().file)
295 }
296 else -> {
297 if (repository.checkNonSystemMessage(message.dataType)) {
298 sendMessageQueue(message)
299 }
300 }
301 }
302 }
303
304 /**
305 * Проверяет наличие сети и инициализирует [SendMessageWorker], если ее нет
306 * @param connection лямда, для отображения соостоянии интернета
307 */
308 private inline fun checkInternetAndInitWorker(connection: (Boolean) -> Unit) {
309 if (!NetworkHelper.checkInternetConnection()) {
310 //Если интернета нет, инициализируем worker
311
312 log(message = "CheckInternetAndInitWorker - Init worker")
313 SendMessageWorker.scheduleMessage(false)
314 //Отмечаем, что отправка запланирована
315 wasScheduled = true
316 //Останавливаем сервис
317 stopSelf()
318 connection(false)
319 } else {
320 log(message = "CheckInternetAndInitWorker - CheckConnection true")
321 connection(true)
322 }
323 }
324
325 /**
326 * Проверяет нужно ли предварительно загружать файл на сервер.
327 */
328 private fun sendOrUploadMessage(message: Message, file: String?) {
329 if (file.isNullOrBlank()) {
330 upload(message)
331 } else {
332 sendMessageQueue(message)
333 }
334 }
335
336 private fun sendMessageSocket() {
337 log(message = "Send message Socket. Message to send size - ${messagesToSend.size}, Message queue size - ${messageQueue.size}")
338 //Если очередь сообщений пуста, вернуться
339 if (messageQueue.isEmpty()) {
340 callSocket = true
341 stopService()
342 return
343 }
344 //Если нет соединения, вернуться.
345 checkInternetAndInitWorker { isConnected ->
346 if (!isConnected) {
347 return@sendMessageSocket
348 }
349 }
350
351 //Получение сообщения из очереди сообщений
352 val message = messageQueue.removeFirst()
353
354 //Добавление сообщения в "отсылаемые"
355 messagesToSend[message.moment] = message
356
357 //Помечает сообщение [Message.STATUS_SENDING]
358 IrbisManager.storage().setSendingMessageStatus(message.localId, Message.STATUS_SENDING)
359 //errorTimerMap[message.localId] = TimerHelper.newInstanceAndStart(timerInterval, SendMessageTimerListener((message)))
360 errorTimer = TimerHelper.newInstanceAndStart(80000, SendMessageTimerListener(message, errorTimer))
361
362 repository.sendMessage(message) { success ->
363 log(message = "Send message $success")
364 if (success) {
365 messagesToSend.remove(message.moment)
366 } else {
367 setErrorMessage(message)
368 }
369 errorTimer?.stop()
370 //errorTimerMap[message.localId]?.stop()
371 sendMessageSocket()
372 }
373 }
374
375 /**
376 * Останавливает сервис, если отсутствуют элементы, которые нужно загрузить
377 */
378 private fun stopService() {
379 if (callSocket
380 && uploadMap.isEmpty()
381 && downloadMap.isEmpty()//observerDownloadMap.isEmpty()
382 && downloadFileMap.isEmpty()//observerDownloadFileMap.isEmpty()
383 && uploadMap.checkIsActive()
384 && downloadMap.checkIsActive()
385 && downloadFileMap.checkIsActive()
386 ) {
387 log(Log.DEBUG, SERVICE_TAG/*STOP_SERVICE_TAG*/, "call stopSelf() on service")
388 stopSelf()
389 }
390 }
391
392 override fun onDestroy() {
393 log(message = "onDestroy")
394 super.onDestroy()
395
396 //Очищаем все Disposable
397 //observerDownloadMap.clearAllDisposable()
398 uploadMap.forEach { it.value.cancel() }
399 downloadMap.forEach { it.value.cancel() }
400 downloadFileMap.forEach { it.value.cancel() }
401
402 //Очищаем Map
403 //observerDownloadMap.clear()
404 uploadMap.clear()
405 downloadMap.clear()
406 downloadFileMap.clear()
407
408 errorTimer?.stop()
409
410 if (!wasScheduled) {
411 if (messageQueue.isNotEmpty()) {
412 messageQueue.forEach { setErrorMessage(it) }
413 messageQueue.clear()
414 } else {
415 messagesToSend.forEach { setErrorMessage(it.value) }
416 messagesToSend.clear()
417 }
418 }
419 }
420
421 private fun stopUpload(message: Message) {
422 log(message = "stop upload message")
423
424 //Проверяем наличие сообщения в отправляемых
425 uploadMap[message.localId]?.let {
426 it.cancel()
427 hideUploadProgressBar(this, message, false)
428 setErrorMessage(message)
429 uploadMap.remove(message.localId)
430 }
431 }
432
433 private fun upload(message: Message) {
434 log(Log.DEBUG, SERVICE_TAG, "upload baseURL $baseURL")
435 //Проверяем наличие сообщения в отправляемых
436 uploadMap[message.localId]?.let {
437 it.cancel()
438 hideUploadProgressBar(this, message, false)
439 IrbisManager.storage().setSendingMessageStatus(message.localId, Message.STATUS_ERROR)
440 uploadMap.remove(message.localId)
441 }
442 if (message.filePath == null) {
443 return
444 }
445 //Устанавливаем начальный процент отправки сообщения
446 publishPercent(this, message, 0, true)
447 //Помечаем сообщение, как "загружаемое"
448 IrbisManager.storage().setSendingMessageStatus(message.localId, Message.STATUS_SENDING)
449 val key: String? = repository.getKey(message)
450 //Для сервера с API выше 5 отправляем сам файл и его превью, для сервера с апи ниже, только файл.
451 val isMultipleFiles: Boolean = message.previewFilePath != null && IrbisManager.settings().apiServer > 5
452
453 val percentLambda: (Int) -> Unit = { percent: Int -> publishPercent(this, message, percent, true) }
454
455 val mapObserver: Job = if (isMultipleFiles) {
456 CoroutineScope(Dispatchers.IO).launch {
457 dataManager.uploadMultipleFilesByFlow(
458 message.filePath,
459 message.previewFilePath,
460 key,
461 restService,
462 percentLambda
463 ).catch {
464 doCatchAction(this@SendDownloadMessageService, message, it.message)
465 }.collect {
466 doCollectAction(message, it, isMultipleFiles)
467 }
468 }
469 } else {
470 CoroutineScope(Dispatchers.IO).launch {
471 dataManager.uploadFileByFlow(
472 message.filePath,
473 key,
474 restService,
475 percentLambda
476 ).catch {
477 doCatchAction(this@SendDownloadMessageService, message, it.message)
478 }.collect {
479 doCollectAction(message, it, isMultipleFiles)
480 }
481 }
482 }
483 uploadMap[message.localId] = mapObserver
484 }
485
486 private fun doCollectAction(message: Message, value: String, isMultipleFiles: Boolean) {
487 log(Log.DEBUG, SERVICE_TAG, "Collect message ${message.localId} with value $value")
488 sendMessageQueue(repository.getPackedMessage(message, value, isMultipleFiles))
489 hideUploadProgressBar(this@SendDownloadMessageService, message, true)
490 uploadMap[message.localId]?.let {
491 it.cancel()
492 uploadMap.remove(message.localId)
493 }
494 stopService()
495 }
496
497 private fun doCatchAction(context: Context, message: Message, errorMessage: String?) {
498 log(Log.DEBUG, SERVICE_TAG, "error while send message $errorMessage")
499 hideUploadProgressBar(context, message, false)
500 setErrorMessage(message)
501 stopService()
502 }
503
504 /**
505 * Загружает сообщение
506 * @param message
507 */
508 private fun download(message: Message) {
509 log(message = "Download message ${message.id}")
510 val file: String = repository.getFile(message) ?: return
511 val key: String? = repository.getKey(message)
512 val extension: String = repository.getExtension(message) ?: return
513 //Если такой DisposableObserver уже существует, очистить,
514 //удалить из map, скрыть прогресс, выйти
515 downloadMap[message.id]?.let {
516 it.cancel()
517 downloadMap.remove(message.id)
518 hideDownloadProgressBar(this, message, false)
519 return
520 }?: kotlin.run {
521 publishPercent(this, message, 0, false)
522 }
523
524 //Создаем рест сервис для отображения загрузки файла/изображения/видео
525 val restService = RestServices.createDownloadRestService(baseURL) { bytesRead, contentLength, done ->
526 repository.getMessageDownloadingPercentage(done, message, bytesRead) {
527 publishPercent(this@SendDownloadMessageService, message, it, false)
528 }
529 }
530
531 val job: Job = CoroutineScope(Dispatchers.IO).launch {
532 dataManager.downloadFile(
533 file,
534 key,
535 extension,
536 restService
537 ).catch {
538 log(message = it.message ?: "unknown exception")
539 hideDownloadProgressBar(this@SendDownloadMessageService, message, false)
540 stopService()
541 }.collect {
542 log(message = "Collect file $file for message ${message.localId}")
543 hideDownloadProgressBar(this@SendDownloadMessageService, message, true)
544 downloadMap[message.id]?.let {
545 downloadMap.remove(message.id)
546 it.cancel()
547 }
548 stopService()
549 }
550 }
551
552 downloadMap[message.id] = job
553 }
554
555 private fun hideDownloadProgressBar(context: Context, message: Message, done: Boolean) {
556 val intent = Intent(NOTIFICATION).apply {
557 putExtra(ACTION, ACTION_HIDE_DOWNLOAD_PROGRESS_BAR)
558 putExtra(CHAT_TYPE, message.chatType)
559 putExtra(CHAT_ID, message.chatId)
560 putExtra(MESSAGE_ID, message.id)
561 putExtra(DONE, done)
562 }
563 context.sendBroadcast(intent)
564 }
565
566 internal inner class SendMessageTimerListener(
567 var message: Message,
568 private var previousTimer: TimerHelper?
569 ) : TimerListener, CoroutineScope by MainScope() {
570 override fun onTimer() {
571 launch {
572 for (message: Message in messageQueue) {
573 setErrorMessage(message)
574 messageQueue.removeFirst()
575 }
576
577 setErrorMessage(message)
578
579 errorTimer?.stop()
580 previousTimer?.stop()
581
582 stopSelf()
583 }
584 }
585 }
586
587 companion object {
588
589 private const val MESSAGE = "message"
590 private const val DATA_ITEM = "data_item"
591 private const val SERVICE_PREFIX = "com.itsoft.lan.irbis.service."
592 private const val ACTION_STOP_UPLOAD = "${SERVICE_PREFIX}ACTION_STOP_UPLOAD"
593 private const val ACTION_START_STOP_UPLOAD = "${SERVICE_PREFIX}ACTION_START_STOP_UPLOAD"
594 private const val ACTION_START_SEND_MESSAGE = "${SERVICE_PREFIX}ACTION_START_SEND_MESSAGE"
595 private const val ACTION_START_STOP_DOWNLOAD = "${SERVICE_PREFIX}ACTION_START_STOP_DOWNLOAD"
596 private const val ACTION_START_STOP_DOWNLOAD_PUBLICATION = "${SERVICE_PREFIX}ACTION_START_STOP_DOWNLOAD_PUBLICATION"
597
598 const val DONE = "done"
599 const val FILE = "file"
600 const val CH_ID = "ch_id"
601 const val LOCAL = "local"
602 const val PUB_ID = "pub_id"
603 const val ACTION = "action"
604 const val CHAT_ID = "chatId"
605 const val PERCENT = "percent"
606 const val LOCAL_ID = "local_id"
607 const val CHAT_TYPE = "chatType"
608 const val MESSAGE_ID = "message_id"
609 const val NOTIFICATION = "com.itsoft.lan.irbis.service"
610 const val ACTION_PUBLISH_PERCENT = "${SERVICE_PREFIX}ACTION_PUBLISH_PERCENT"
611 const val ACTION_HIDE_UPLOAD_PROGRESS_BAR = "${SERVICE_PREFIX}ACTION_HIDE_UPLOAD_PROGRESS_BAR"
612 const val ACTION_PUBLISH_PUBLICATION_ERROR = "${SERVICE_PREFIX}ACTION_PUBLISH_PUBLICATION_ERROR"
613 const val ACTION_HIDE_DOWNLOAD_PROGRESS_BAR = "${SERVICE_PREFIX}ACTION_HIDE_DOWNLOAD_PROGRESS_BAR"
614 const val ACTION_PUBLISH_PUBLICATION_PERCENT = "${SERVICE_PREFIX}ACTION_PUBLISH_PUBLICATION_PERCENT"
615 const val ACTION_HIDE_DOWNLOAD_PUBLICATION_PROGRESS_BAR = "${SERVICE_PREFIX}ACTION_HIDE_DOWNLOAD_PUBLICATION_PROGRESS_BAR"
616
617
618 private const val SERVICE_TAG: String = "ServiceTag"
619 private const val PUBLISH_PERCENT: String = "PublishPercent"
620
621 fun stopUpload(context: Context, message: Message?) {
622 message?.let {
623 val intent = Intent(context, SendDownloadMessageService::class.java).apply {
624 putExtra(ACTION, ACTION_STOP_UPLOAD)
625 putExtra(MESSAGE, it)
626 }
627 context.startService(intent)
628 }
629 }
630
631 fun startStopUpload(context: Context, message: Message?) {
632 val intent = Intent(context, SendDownloadMessageService::class.java).apply {
633 putExtra(ACTION, ACTION_START_STOP_UPLOAD)
634 putExtra(MESSAGE, message)
635 }
636 context.startService(intent)
637 }
638
639 @JvmStatic
640 fun startSendMessage(context: Context, message: Message?) {
641 val intent = Intent(context, SendDownloadMessageService::class.java).apply {
642 putExtra(ACTION, ACTION_START_SEND_MESSAGE)
643 putExtra(MESSAGE, message)
644 }
645 context.startService(intent)
646 }
647
648 @JvmStatic
649 fun publishPercent(context: Context, message: Message, percent: Int, local: Boolean) {
650 log(tag = PUBLISH_PERCENT, message = "publish percent $percent for message ${message.localId}")
651 val intent = Intent(NOTIFICATION).apply {
652 putExtra(ACTION, ACTION_PUBLISH_PERCENT)
653 putExtra(CHAT_TYPE, message.chatType)
654 putExtra(CHAT_ID, message.chatId)
655 putExtra(PERCENT, percent)
656 putExtra(LOCAL, local)
657 //Если сообщение локально (еще не отправилось) добавляем локальный id
658 putExtra(MESSAGE_ID, if (local) message.localId else message.id)
659 }
660 context.sendBroadcast(intent)
661 }
662
663 @JvmStatic
664 fun hideUploadProgressBar(context: Context, message: Message, done: Boolean) {
665 log(message = "hide upload progress bar ${message.localId}")
666 val intent = Intent(NOTIFICATION).apply {
667 putExtra(ACTION, ACTION_HIDE_UPLOAD_PROGRESS_BAR)
668 putExtra(CHAT_TYPE, message.chatType)
669 putExtra(CHAT_ID, message.chatId)
670 putExtra(LOCAL_ID, message.localId)
671 putExtra(DONE, done)
672 }
673 context.sendBroadcast(intent)
674 }
675
676 private fun log(priority: Int = Log.DEBUG, tag: String = SERVICE_TAG, message: String) = LogUtils.log(priority, tag, message)
677 }
678}