parent
							
								
									cd8615075c
								
							
						
					
					
						commit
						e55227a2a9
					
				| @ -1,46 +1,172 @@ | ||||
| package io.legado.app.service | ||||
| 
 | ||||
| import android.app.DownloadManager | ||||
| import android.content.BroadcastReceiver | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.content.IntentFilter | ||||
| import android.os.Handler | ||||
| import androidx.core.app.NotificationCompat | ||||
| import androidx.core.os.bundleOf | ||||
| import io.legado.app.R | ||||
| import io.legado.app.base.BaseService | ||||
| import io.legado.app.constant.AppConst | ||||
| import io.legado.app.constant.IntentAction | ||||
| import io.legado.app.help.IntentHelp | ||||
| import org.jetbrains.anko.downloadManager | ||||
| import org.jetbrains.anko.notificationManager | ||||
| 
 | ||||
| 
 | ||||
| class DownloadService : BaseService() { | ||||
| 
 | ||||
|     private val notificationBuilder by lazy { | ||||
|         val builder = NotificationCompat.Builder(this, AppConst.channelIdDownload) | ||||
|             .setSmallIcon(R.drawable.ic_download) | ||||
|             .setOngoing(true) | ||||
|             .setContentTitle(getString(R.string.action_download)) | ||||
|         builder.addAction( | ||||
|             R.drawable.ic_stop_black_24dp, | ||||
|             getString(R.string.cancel), | ||||
|             IntentHelp.servicePendingIntent<DownloadService>(this, IntentAction.stop) | ||||
|         ) | ||||
|         builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||
|     private val downloads = hashMapOf<Long, String>() | ||||
|     private val completeDownloads = hashSetOf<Long>() | ||||
|     private val handler = Handler() | ||||
|     private val runnable = Runnable { | ||||
|         checkDownloadState() | ||||
|     } | ||||
| 
 | ||||
|     private val downloadReceiver = object : BroadcastReceiver() { | ||||
|         override fun onReceive(context: Context, intent: Intent) { | ||||
|             queryState() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun onCreate() { | ||||
|         super.onCreate() | ||||
|         updateNotification("准备下载") | ||||
|         registerReceiver(downloadReceiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) | ||||
|     } | ||||
| 
 | ||||
|     override fun onTaskRemoved(rootIntent: Intent?) { | ||||
|         super.onTaskRemoved(rootIntent) | ||||
|         stopSelf() | ||||
|     } | ||||
| 
 | ||||
|     override fun onDestroy() { | ||||
|         super.onDestroy() | ||||
|         unregisterReceiver(downloadReceiver) | ||||
|     } | ||||
| 
 | ||||
|     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { | ||||
|         when (intent?.action) { | ||||
| 
 | ||||
|             IntentAction.start -> startDownload( | ||||
|                 intent.getLongExtra("downloadId", 0), | ||||
|                 intent.getStringExtra("fileName") ?: "未知文件" | ||||
|             ) | ||||
|             IntentAction.play -> { | ||||
|                 val id = intent.getLongExtra("downloadId", 0) | ||||
|                 if (downloads[id]?.endsWith(".apk") == true) { | ||||
|                     installApk(id) | ||||
|                 } | ||||
|             } | ||||
|             IntentAction.stop -> { | ||||
|                 val downloadId = intent.getLongExtra("downloadId", 0) | ||||
|                 if (downloadId > 0) { | ||||
|                     downloadManager.remove(downloadId) | ||||
|                     notificationManager.cancel(downloadId.toInt()) | ||||
|                 } else { | ||||
|                     stopSelf() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return super.onStartCommand(intent, flags, startId) | ||||
|     } | ||||
| 
 | ||||
|     private fun startDownload(downloadId: Long, fileName: String) { | ||||
|         if (downloadId > 0) { | ||||
|             downloads[downloadId] = fileName | ||||
|             queryState() | ||||
|             checkDownloadState() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun checkDownloadState() { | ||||
|         handler.removeCallbacks(runnable) | ||||
|         queryState() | ||||
|         handler.postDelayed(runnable, 1000) | ||||
|     } | ||||
| 
 | ||||
|     //查询下载进度 | ||||
|     private fun queryState() { | ||||
|         val ids = downloads.keys | ||||
|         val query = DownloadManager.Query() | ||||
|         query.setFilterById(*ids.toLongArray()) | ||||
|         val cursor = downloadManager.query(query) | ||||
|         if (!cursor.moveToFirst()) return | ||||
|         val id = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID)) | ||||
|         val progress: Int = | ||||
|             cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) | ||||
|         val max: Int = | ||||
|             cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)) | ||||
|         val status = when (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))) { | ||||
|             DownloadManager.STATUS_PAUSED -> "暂停" | ||||
|             DownloadManager.STATUS_PENDING -> "待下载" | ||||
|             DownloadManager.STATUS_RUNNING -> "下载中" | ||||
|             DownloadManager.STATUS_SUCCESSFUL -> { | ||||
|                 if (!completeDownloads.contains(id)) { | ||||
|                     completeDownloads.add(id) | ||||
|                     if (downloads[id]?.endsWith(".apk") == true) { | ||||
|                         installApk(id) | ||||
|                     } | ||||
|                 } | ||||
|                 "下载完成" | ||||
|             } | ||||
|             DownloadManager.STATUS_FAILED -> "下载失败" | ||||
|             else -> "未知状态" | ||||
|         } | ||||
|         updateNotification(id, "${downloads[id]} $status", max, progress) | ||||
|         if (!cursor.isClosed) { | ||||
|             cursor.close() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun installApk(downloadId: Long) { | ||||
|         val downloadFileUri = downloadManager.getUriForDownloadedFile(downloadId) | ||||
|         downloadFileUri?.let { | ||||
|             val install = Intent(Intent.ACTION_VIEW) | ||||
|             install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive") | ||||
|             install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) | ||||
|             startActivity(install) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 更新通知 | ||||
|      */ | ||||
|     private fun updateNotification(content: String) { | ||||
|     private fun updateNotification(downloadId: Long, content: String, max: Int, progress: Int) { | ||||
|         val notificationBuilder = NotificationCompat.Builder(this, AppConst.channelIdDownload) | ||||
|             .setSmallIcon(R.drawable.ic_download) | ||||
|             .setOngoing(true) | ||||
|             .setContentTitle(getString(R.string.action_download)) | ||||
|         notificationBuilder.setContentIntent( | ||||
|             IntentHelp.servicePendingIntent<DownloadService>( | ||||
|                 this, | ||||
|                 IntentAction.play, | ||||
|                 bundleOf("downloadId" to downloadId) | ||||
|             ) | ||||
|         ) | ||||
|         notificationBuilder.addAction( | ||||
|             R.drawable.ic_stop_black_24dp, | ||||
|             getString(R.string.cancel), | ||||
|             IntentHelp.servicePendingIntent<DownloadService>( | ||||
|                 this, | ||||
|                 IntentAction.stop, | ||||
|                 bundleOf("downloadId" to downloadId) | ||||
|             ) | ||||
|         ) | ||||
|         notificationBuilder.setDeleteIntent( | ||||
|             IntentHelp.servicePendingIntent<DownloadService>( | ||||
|                 this, | ||||
|                 IntentAction.stop, | ||||
|                 bundleOf("downloadId" to downloadId) | ||||
|             ) | ||||
|         ) | ||||
|         notificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||
|         notificationBuilder.setContentText(content) | ||||
|         notificationBuilder.setProgress(max, progress, false) | ||||
|         notificationBuilder.setAutoCancel(true) | ||||
|         val notification = notificationBuilder.build() | ||||
|         startForeground(AppConst.notificationIdDownload, notification) | ||||
|         startForeground(downloadId.toInt(), notification) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,26 @@ | ||||
| package io.legado.app.service.help | ||||
| 
 | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import io.legado.app.constant.IntentAction | ||||
| import io.legado.app.service.DownloadService | ||||
| 
 | ||||
| object Download { | ||||
| 
 | ||||
|     fun start(context: Context, downloadId: Long, fileName: String) { | ||||
|         Intent(context, DownloadService::class.java).let { | ||||
|             it.action = IntentAction.start | ||||
|             it.putExtra("downloadId", downloadId) | ||||
|             it.putExtra("fileName", fileName) | ||||
|             context.startService(it) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun stop(context: Context) { | ||||
|         Intent(context, DownloadService::class.java).let { | ||||
|             it.action = IntentAction.stop | ||||
|             context.startService(it) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue