diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6b1aac312..40e579466 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -61,7 +61,7 @@
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/Service.kt b/app/src/main/java/com/topjohnwu/magisk/core/Service.kt
new file mode 100644
index 000000000..5398c8497
--- /dev/null
+++ b/app/src/main/java/com/topjohnwu/magisk/core/Service.kt
@@ -0,0 +1,40 @@
+package com.topjohnwu.magisk.core
+
+import android.app.Notification
+import android.content.Intent
+import android.os.Build
+import androidx.core.app.ServiceCompat
+import androidx.core.content.IntentCompat
+import com.topjohnwu.magisk.core.base.BaseService
+import com.topjohnwu.magisk.core.download.DownloadManager
+import com.topjohnwu.magisk.core.download.Subject
+
+class Service : BaseService(), DownloadManager.Session {
+
+ private lateinit var dm: DownloadManager
+ override val context get() = this
+
+ override fun onCreate() {
+ super.onCreate()
+ dm = DownloadManager(this)
+ }
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ if (intent.action == DownloadManager.ACTION) {
+ IntentCompat
+ .getParcelableExtra(intent, DownloadManager.SUBJECT_KEY, Subject::class.java)
+ ?.let { dm.download(it) }
+ }
+ return START_NOT_STICKY
+ }
+
+ override fun attach(id: Int, builder: Notification.Builder) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
+ builder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
+ startForeground(id, builder.build())
+ }
+
+ override fun stop() {
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
+ }
+}
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadManager.kt
similarity index 50%
rename from app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt
rename to app/src/main/java/com/topjohnwu/magisk/core/download/DownloadManager.kt
index 591a3c457..20de8f0be 100644
--- a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadManager.kt
@@ -2,30 +2,41 @@ package com.topjohnwu.magisk.core.download
import android.Manifest
import android.annotation.SuppressLint
+import android.app.Notification
import android.app.PendingIntent
-import android.app.PendingIntent.*
import android.content.Context
-import android.content.Intent
import android.net.Uri
import android.os.Build
+import androidx.collection.SparseArrayCompat
+import androidx.collection.isNotEmpty
import androidx.core.net.toFile
import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.ActivityTracker
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.BaseActivity
+import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.core.isRunningAsStub
-import com.topjohnwu.magisk.core.ktx.*
+import com.topjohnwu.magisk.core.ktx.copyAndClose
+import com.topjohnwu.magisk.core.ktx.forEach
+import com.topjohnwu.magisk.core.ktx.selfLaunchIntent
+import com.topjohnwu.magisk.core.ktx.set
+import com.topjohnwu.magisk.core.ktx.withStreams
+import com.topjohnwu.magisk.core.ktx.writeTo
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
+import com.topjohnwu.magisk.core.utils.ProgressInputStream
import com.topjohnwu.magisk.utils.APKInstall
+import com.topjohnwu.magisk.view.Notifications
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
+import okhttp3.ResponseBody
import timber.log.Timber
import java.io.ByteArrayInputStream
import java.io.IOException
@@ -37,27 +48,77 @@ import java.util.zip.ZipFile
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
-class DownloadService : NotificationService() {
+class DownloadManager(
+ private val session: Session
+) {
+
+ interface Session {
+ val context: Context
- private val job = Job()
-
- override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- intent.getParcelableExtra(SUBJECT_KEY)?.let { download(it) }
- return START_NOT_STICKY
+ fun attach(id: Int, notification: Notification.Builder)
+ fun stop()
}
- override fun onDestroy() {
- job.cancel()
+ companion object {
+ const val ACTION = "com.topjohnwu.magisk.DOWNLOAD"
+ const val SUBJECT_KEY = "subject"
+ private const val REQUEST_CODE = 1
+
+ private val progressBroadcast = MutableLiveData?>()
+
+ private fun broadcast(progress: Float, subject: Subject) {
+ progressBroadcast.postValue(progress to subject)
+ }
+
+ fun observeProgress(owner: LifecycleOwner, callback: (Float, Subject) -> Unit) {
+ progressBroadcast.value = null
+ progressBroadcast.observe(owner) {
+ val (progress, subject) = it ?: return@observe
+ callback(progress, subject)
+ }
+ }
+
+ private fun createIntent(context: Context, subject: Subject) =
+ context.intent()
+ .setAction(ACTION)
+ .putExtra(SUBJECT_KEY, subject)
+
+ @SuppressLint("InlinedApi")
+ fun getPendingIntent(context: Context, subject: Subject): PendingIntent {
+ val flag = PendingIntent.FLAG_IMMUTABLE or
+ PendingIntent.FLAG_UPDATE_CURRENT or
+ PendingIntent.FLAG_ONE_SHOT
+ val intent = createIntent(context, subject)
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ PendingIntent.getForegroundService(context, REQUEST_CODE, intent, flag)
+ } else {
+ PendingIntent.getService(context, REQUEST_CODE, intent, flag)
+ }
+ }
+
+ @SuppressLint("InlinedApi")
+ fun start(activity: BaseActivity, subject: Subject) {
+ activity.withPermission(Manifest.permission.POST_NOTIFICATIONS) {
+ // Always download regardless of notification permission status
+ val app = activity.applicationContext
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ app.startForegroundService(createIntent(app, subject))
+ } else {
+ app.startService(createIntent(app, subject))
+ }
+ }
+ }
}
- private fun download(subject: Subject) {
+ fun download(subject: Subject) {
notifyUpdate(subject.notifyId)
CoroutineScope(job + Dispatchers.IO).launch {
try {
- val stream = service.fetchFile(subject.url).toProgressStream(subject)
+ val stream = network.fetchFile(subject.url).toProgressStream(subject)
when (subject) {
is Subject.App -> handleApp(stream, subject)
is Subject.Module -> handleModule(stream, subject.file)
+ is Subject.Test -> stream.copyAndClose(subject.file.outputStream())
}
val activity = ActivityTracker.foreground
if (activity != null && subject.autoLaunch) {
@@ -67,15 +128,99 @@ class DownloadService : NotificationService() {
notifyFinish(subject)
}
subject.postDownload?.invoke()
- if (!hasNotifications)
- stopSelf()
} catch (e: Exception) {
Timber.e(e)
notifyFail(subject)
}
+
+ synchronized(this@DownloadManager) {
+ if (notifications.isEmpty)
+ session.stop()
+ }
}
}
+ private val notifications = SparseArrayCompat()
+ private var attachedId = -1
+
+ private val job = Job()
+
+ private val context get() = session.context
+ private val network get() = ServiceLocator.networkService
+
+ private fun finalNotify(id: Int, editor: (Notification.Builder) -> Unit): Int {
+ val notification = notifyRemove(id)?.also(editor) ?: return -1
+ val newId = Notifications.nextId()
+ Notifications.mgr.notify(newId, notification.build())
+ return newId
+ }
+
+ private fun notifyFail(subject: Subject) = finalNotify(subject.notifyId) {
+ broadcast(-2f, subject)
+ it.setContentText(context.getString(R.string.download_file_error))
+ .setSmallIcon(android.R.drawable.stat_notify_error)
+ .setOngoing(false)
+ }
+
+ private fun notifyFinish(subject: Subject) = finalNotify(subject.notifyId) {
+ broadcast(1f, subject)
+ it.setContentTitle(subject.title)
+ .setContentText(context.getString(R.string.download_complete))
+ .setSmallIcon(android.R.drawable.stat_sys_download_done)
+ .setProgress(0, 0, false)
+ .setOngoing(false)
+ .setAutoCancel(true)
+ subject.pendingIntent(context)?.let { intent -> it.setContentIntent(intent) }
+ }
+
+ private fun attachNotification(id: Int, notification: Notification.Builder) {
+ attachedId = id
+ session.attach(id, notification)
+ }
+
+ @Synchronized
+ private fun notifyUpdate(id: Int, editor: (Notification.Builder) -> Unit = {}) {
+ val notification = (notifications[id] ?: Notifications.startProgress("").also {
+ notifications[id] = it
+ }).apply(editor)
+
+ if (attachedId < 0)
+ attachNotification(id, notification)
+ else
+ Notifications.mgr.notify(id, notification.build())
+ }
+
+ @Synchronized
+ private fun notifyRemove(id: Int): Notification.Builder? {
+ val idx = notifications.indexOfKey(id)
+ var n: Notification.Builder? = null
+
+ if (idx >= 0) {
+ n = notifications.valueAt(idx)
+ notifications.removeAt(idx)
+
+ // The cancelled notification is the one attached to the session, need special handling
+ if (attachedId == id) {
+ if (notifications.isNotEmpty()) {
+ // There are still remaining notifications, pick one and attach to the session
+ val anotherId = notifications.keyAt(0)
+ val notification = notifications.valueAt(0)
+ // Attaching a new notification will automatically remove the current one
+ attachNotification(anotherId, notification)
+ } else {
+ // No more notifications left, terminate the session
+ attachedId = -1
+ session.stop()
+ }
+
+ return n
+ }
+ }
+
+ Notifications.mgr.cancel(id)
+ return n
+ }
+
private fun handleApp(stream: InputStream, subject: Subject.App) {
fun writeTee(output: OutputStream) {
val uri = MediaStoreUtils.getFile("${subject.title}.apk").uri
@@ -84,7 +229,7 @@ class DownloadService : NotificationService() {
}
if (isRunningAsStub) {
- val updateApk = StubApk.update(this)
+ val updateApk = StubApk.update(context)
try {
// Download full APK to stub update path
writeTee(updateApk.outputStream())
@@ -97,7 +242,7 @@ class DownloadService : NotificationService() {
// Also upgrade stub
notifyUpdate(subject.notifyId) {
it.setProgress(0, 0, true)
- .setContentTitle(getString(R.string.hide_app_title))
+ .setContentTitle(context.getString(R.string.hide_app_title))
.setContentText("")
}
@@ -107,7 +252,7 @@ class DownloadService : NotificationService() {
zf.close()
// Patch and install
- subject.intent = HideAPK.upgrade(this, apk)
+ subject.intent = HideAPK.upgrade(context, apk)
?: throw IOException("HideAPK patch error")
apk.delete()
} else {
@@ -116,7 +261,7 @@ class DownloadService : NotificationService() {
StubApk.restartProcess(it)
} ?: run {
// Or else kill the current process after posting notification
- subject.intent = selfLaunchIntent()
+ subject.intent = context.selfLaunchIntent()
subject.postDownload = { Runtime.getRuntime().exit(0) }
}
return
@@ -127,8 +272,8 @@ class DownloadService : NotificationService() {
throw e
}
} else {
- val session = APKInstall.startSession(this)
- writeTee(session.openStream(this))
+ val session = APKInstall.startSession(context)
+ writeTee(session.openStream(context))
subject.intent = session.waitIntent()
}
}
@@ -143,7 +288,7 @@ class DownloadService : NotificationService() {
zout.putNextEntry(ZipEntry("META-INF/com/google/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/android/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary"))
- assets.open("module_installer.sh").copyTo(zout)
+ context.assets.open("module_installer.sh").copyTo(zout)
zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script"))
zout.write("#MAGISK\n".toByteArray())
@@ -178,41 +323,24 @@ class DownloadService : NotificationService() {
}
}
- companion object {
- private const val SUBJECT_KEY = "subject"
- private const val REQUEST_CODE = 1
+ private fun ResponseBody.toProgressStream(subject: Subject): InputStream {
+ val max = contentLength()
+ val total = max.toFloat() / 1048576
+ val id = subject.notifyId
- fun observeProgress(owner: LifecycleOwner, callback: (Float, Subject) -> Unit) {
- progressBroadcast.value = null
- progressBroadcast.observe(owner) {
- val (progress, subject) = it ?: return@observe
- callback(progress, subject)
- }
- }
+ notifyUpdate(id) { it.setContentTitle(subject.title) }
- private fun intent(context: Context, subject: Subject) =
- context.intent().putExtra(SUBJECT_KEY, subject)
-
- @SuppressLint("InlinedApi")
- fun getPendingIntent(context: Context, subject: Subject): PendingIntent {
- val flag = FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT or FLAG_ONE_SHOT
- val intent = intent(context, subject)
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- getForegroundService(context, REQUEST_CODE, intent, flag)
- } else {
- getService(context, REQUEST_CODE, intent, flag)
- }
- }
-
- @SuppressLint("InlinedApi")
- fun start(activity: BaseActivity, subject: Subject) {
- activity.withPermission(Manifest.permission.POST_NOTIFICATIONS) {
- // Always download regardless of notification permission status
- val app = activity.applicationContext
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- app.startForegroundService(intent(app, subject))
+ return ProgressInputStream(byteStream()) {
+ val progress = it.toFloat() / 1048576
+ notifyUpdate(id) { notification ->
+ if (max > 0) {
+ broadcast(progress / total, subject)
+ notification
+ .setProgress(max.toInt(), it.toInt(), false)
+ .setContentText("%.2f / %.2f MB".format(progress, total))
} else {
- app.startService(intent(app, subject))
+ broadcast(-1f, subject)
+ notification.setContentText("%.2f MB / ??".format(progress))
}
}
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/NotificationService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/NotificationService.kt
deleted file mode 100644
index ef7c4c55d..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/core/download/NotificationService.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.topjohnwu.magisk.core.download
-
-import android.app.Notification
-import android.content.Intent
-import android.os.Build
-import androidx.lifecycle.MutableLiveData
-import com.topjohnwu.magisk.R
-import com.topjohnwu.magisk.core.base.BaseService
-import com.topjohnwu.magisk.core.di.ServiceLocator
-import com.topjohnwu.magisk.core.ktx.synchronized
-import com.topjohnwu.magisk.core.utils.ProgressInputStream
-import com.topjohnwu.magisk.view.Notifications
-import okhttp3.ResponseBody
-import java.io.InputStream
-
-open class NotificationService : BaseService() {
-
- private val notifications = HashMap().synchronized()
- protected val hasNotifications get() = notifications.isNotEmpty()
-
- protected val service get() = ServiceLocator.networkService
-
- private var attachedNotificationId = 0
-
- override fun onTaskRemoved(rootIntent: Intent?) {
- super.onTaskRemoved(rootIntent)
- notifications.forEach { Notifications.mgr.cancel(it.key) }
- notifications.clear()
- }
-
- protected fun ResponseBody.toProgressStream(subject: Subject): InputStream {
- val max = contentLength()
- val total = max.toFloat() / 1048576
- val id = subject.notifyId
-
- notifyUpdate(id) { it.setContentTitle(subject.title) }
-
- return ProgressInputStream(byteStream()) {
- val progress = it.toFloat() / 1048576
- notifyUpdate(id) { notification ->
- if (max > 0) {
- broadcast(progress / total, subject)
- notification
- .setProgress(max.toInt(), it.toInt(), false)
- .setContentText("%.2f / %.2f MB".format(progress, total))
- } else {
- broadcast(-1f, subject)
- notification.setContentText("%.2f MB / ??".format(progress))
- }
- }
- }
- }
-
- private fun finalNotify(id: Int, editor: (Notification.Builder) -> Unit): Int {
- val notification = notifyRemove(id)?.also(editor) ?: return -1
- val newId = Notifications.nextId()
- Notifications.mgr.notify(newId, notification.build())
- return newId
- }
-
- protected fun notifyFail(subject: Subject) = finalNotify(subject.notifyId) {
- broadcast(-2f, subject)
- it.setContentText(getString(R.string.download_file_error))
- .setSmallIcon(android.R.drawable.stat_notify_error)
- .setOngoing(false)
- }
-
- protected fun notifyFinish(subject: Subject) = finalNotify(subject.notifyId) {
- broadcast(1f, subject)
- it.setContentTitle(subject.title)
- .setContentText(getString(R.string.download_complete))
- .setSmallIcon(android.R.drawable.stat_sys_download_done)
- .setProgress(0, 0, false)
- .setOngoing(false)
- .setAutoCancel(true)
- subject.pendingIntent(this)?.let { intent -> it.setContentIntent(intent) }
- }
-
- private fun attachNotification(id: Int, notification: Notification) {
- attachedNotificationId = id
- startForeground(id, notification)
- }
-
- private fun maybeDetachNotification(id: Int) : Boolean {
- if (attachedNotificationId != id) return false
- if (hasNotifications) {
- val (anotherId, notification) = notifications.entries.first()
- // Attaching a new notification will remove the current showing one
- attachNotification(anotherId, notification.build())
- return true
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- stopForeground(STOP_FOREGROUND_REMOVE)
- } else {
- @Suppress("DEPRECATION")
- stopForeground(true)
- }
- attachedNotificationId = 0
- return true
- }
-
- protected fun notifyUpdate(id: Int, editor: (Notification.Builder) -> Unit = {}) {
- fun create() = Notifications.startProgress("")
-
- val wasEmpty = !hasNotifications
- val notification = notifications.getOrPut(id, ::create).also(editor).build()
- if (wasEmpty)
- attachNotification(id, notification)
- else
- Notifications.mgr.notify(id, notification)
- }
-
- protected fun notifyRemove(id: Int): Notification.Builder? {
- val n = notifications.remove(id)
- if (n == null || !maybeDetachNotification(id))
- Notifications.mgr.cancel(id)
- return n
- }
-
- companion object {
- @JvmStatic
- protected val progressBroadcast = MutableLiveData?>()
-
- private fun broadcast(progress: Float, subject: Subject) {
- progressBroadcast.postValue(progress to subject)
- }
- }
-}
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
index 4c9ea4600..c0e93fe50 100644
--- a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
@@ -17,8 +17,8 @@ import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.view.Notifications
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
-
-private fun cachedFile(name: String) = AppContext.cachedFile(name).apply { delete() }.toUri()
+import java.io.File
+import java.util.UUID
enum class Action {
Flash,
@@ -34,7 +34,7 @@ sealed class Subject : Parcelable {
open val autoLaunch: Boolean get() = true
open val postDownload: (() -> Unit)? get() = null
- abstract fun pendingIntent(context: Context): PendingIntent?
+ open fun pendingIntent(context: Context): PendingIntent? = null
@Parcelize
class Module(
@@ -65,7 +65,7 @@ sealed class Subject : Parcelable {
@IgnoredOnParcel
override val file by lazy {
- cachedFile("manager.apk")
+ AppContext.cachedFile("manager.apk").apply { delete() }.toUri()
}
@IgnoredOnParcel
@@ -76,6 +76,16 @@ sealed class Subject : Parcelable {
override fun pendingIntent(context: Context) = intent?.toPending(context)
}
+ @Parcelize
+ class Test(
+ override val notifyId: Int = Notifications.nextId(),
+ override val title: String = UUID.randomUUID().toString().substring(0, 6)
+ ) : Subject() {
+ override val url get() = "http://link.testfile.org/150MB"
+ override val file get() = File("/dev/null").toUri()
+ override val autoLaunch get() = false
+ }
+
@SuppressLint("InlinedApi")
protected fun Intent.toPending(context: Context): PendingIntent {
return PendingIntent.getActivity(context, notifyId, this,
diff --git a/app/src/main/java/com/topjohnwu/magisk/dialog/ManagerInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/dialog/ManagerInstallDialog.kt
index f29c26ee9..7d14d7df6 100644
--- a/app/src/main/java/com/topjohnwu/magisk/dialog/ManagerInstallDialog.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/dialog/ManagerInstallDialog.kt
@@ -4,7 +4,7 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.di.ServiceLocator
-import com.topjohnwu.magisk.core.download.DownloadService
+import com.topjohnwu.magisk.core.download.DownloadManager
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.view.MagiskDialog
import java.io.File
@@ -29,7 +29,7 @@ class ManagerInstallDialog : MarkDownDialog() {
setCancelable(true)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.install
- onClick { DownloadService.start(activity, Subject.App()) }
+ onClick { DownloadManager.start(activity, Subject.App()) }
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
diff --git a/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt
index 2ed97705b..85a19f4dc 100644
--- a/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt
@@ -3,7 +3,7 @@ package com.topjohnwu.magisk.dialog
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.download.Action
-import com.topjohnwu.magisk.core.download.DownloadService
+import com.topjohnwu.magisk.core.download.DownloadManager
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.view.MagiskDialog
@@ -24,7 +24,7 @@ class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog
fun download(install: Boolean) {
val action = if (install) Action.Flash else Action.Download
val subject = Subject.Module(item, action)
- DownloadService.start(activity, subject)
+ DownloadManager.start(activity, subject)
}
val title = context.getString(R.string.repo_install_title,
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt
index 72c52c7c7..2a7bcc6df 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt
@@ -14,7 +14,7 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Info
-import com.topjohnwu.magisk.core.download.DownloadService
+import com.topjohnwu.magisk.core.download.DownloadManager
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
class HomeFragment : BaseFragment(), MenuProvider {
@@ -25,7 +25,7 @@ class HomeFragment : BaseFragment(), MenuProvider {
override fun onStart() {
super.onStart()
activity?.setTitle(R.string.section_home)
- DownloadService.observeProgress(this, viewModel::onProgressUpdate)
+ DownloadManager.observeProgress(this, viewModel::onProgressUpdate)
}
private fun checkTitle(text: TextView, icon: ImageView) {
diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt
index 229139e6a..c3fcd7c13 100644
--- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt
@@ -11,7 +11,7 @@ import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toIcon
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.AppContext
-import com.topjohnwu.magisk.core.download.DownloadService
+import com.topjohnwu.magisk.core.download.DownloadManager
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.ktx.getBitmap
import com.topjohnwu.magisk.core.ktx.selfLaunchIntent
@@ -67,7 +67,7 @@ object Notifications {
fun updateAvailable() {
AppContext.apply {
- val intent = DownloadService.getPendingIntent(this, Subject.App())
+ val intent = DownloadManager.getPendingIntent(this, Subject.App())
val bitmap = getBitmap(R.drawable.ic_magisk_outline)
val builder = if (SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder(this, UPDATE_CHANNEL)