parent
cd8615075c
commit
e55227a2a9
@ -1,46 +1,172 @@ |
|||||||
package io.legado.app.service |
package io.legado.app.service |
||||||
|
|
||||||
|
import android.app.DownloadManager |
||||||
|
import android.content.BroadcastReceiver |
||||||
|
import android.content.Context |
||||||
import android.content.Intent |
import android.content.Intent |
||||||
|
import android.content.IntentFilter |
||||||
|
import android.os.Handler |
||||||
import androidx.core.app.NotificationCompat |
import androidx.core.app.NotificationCompat |
||||||
|
import androidx.core.os.bundleOf |
||||||
import io.legado.app.R |
import io.legado.app.R |
||||||
import io.legado.app.base.BaseService |
import io.legado.app.base.BaseService |
||||||
import io.legado.app.constant.AppConst |
import io.legado.app.constant.AppConst |
||||||
import io.legado.app.constant.IntentAction |
import io.legado.app.constant.IntentAction |
||||||
import io.legado.app.help.IntentHelp |
import io.legado.app.help.IntentHelp |
||||||
|
import org.jetbrains.anko.downloadManager |
||||||
|
import org.jetbrains.anko.notificationManager |
||||||
|
|
||||||
|
|
||||||
class DownloadService : BaseService() { |
class DownloadService : BaseService() { |
||||||
|
|
||||||
private val notificationBuilder by lazy { |
private val downloads = hashMapOf<Long, String>() |
||||||
val builder = NotificationCompat.Builder(this, AppConst.channelIdDownload) |
private val completeDownloads = hashSetOf<Long>() |
||||||
.setSmallIcon(R.drawable.ic_download) |
private val handler = Handler() |
||||||
.setOngoing(true) |
private val runnable = Runnable { |
||||||
.setContentTitle(getString(R.string.action_download)) |
checkDownloadState() |
||||||
builder.addAction( |
} |
||||||
R.drawable.ic_stop_black_24dp, |
|
||||||
getString(R.string.cancel), |
private val downloadReceiver = object : BroadcastReceiver() { |
||||||
IntentHelp.servicePendingIntent<DownloadService>(this, IntentAction.stop) |
override fun onReceive(context: Context, intent: Intent) { |
||||||
) |
queryState() |
||||||
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) |
} |
||||||
} |
} |
||||||
|
|
||||||
override fun onCreate() { |
override fun onCreate() { |
||||||
super.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 { |
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { |
||||||
when (intent?.action) { |
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) |
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.setContentText(content) |
||||||
|
notificationBuilder.setProgress(max, progress, false) |
||||||
|
notificationBuilder.setAutoCancel(true) |
||||||
val notification = notificationBuilder.build() |
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