Magisk/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt

164 lines
6.0 KiB
Kotlin
Raw Normal View History

package com.topjohnwu.magisk.model.download
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.webkit.MimeTypeMap
import androidx.core.app.NotificationCompat
2019-10-16 11:07:29 +02:00
import com.topjohnwu.magisk.ProcessPhoenix
import com.topjohnwu.magisk.R
2019-07-28 11:10:22 +02:00
import com.topjohnwu.magisk.extensions.chooser
import com.topjohnwu.magisk.extensions.exists
2019-07-28 11:10:22 +02:00
import com.topjohnwu.magisk.extensions.provide
2019-10-16 10:38:31 +02:00
import com.topjohnwu.magisk.intent
2019-07-10 18:45:34 +02:00
import com.topjohnwu.magisk.model.entity.internal.Configuration.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
import com.topjohnwu.magisk.ui.flash.FlashActivity
import com.topjohnwu.magisk.utils.APKInstall
2019-10-16 11:07:29 +02:00
import com.topjohnwu.magisk.utils.DynAPK
import com.topjohnwu.magisk.isRunningAsStub
import org.koin.core.get
import java.io.File
import kotlin.random.Random.Default.nextInt
/* More of a facade for [RemoteFileService], but whatever... */
@SuppressLint("Registered")
open class DownloadService : RemoteFileService() {
private val context get() = this
private val File.type
get() = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(extension)
?: "resource/folder"
2019-08-22 21:05:41 +02:00
override fun onFinished(subject: DownloadSubject, id: Int) = when (subject) {
is Magisk -> onFinishedInternal(subject, id)
is Module -> onFinishedInternal(subject, id)
is Manager -> onFinishedInternal(subject, id)
}
private fun onFinishedInternal(
2019-07-25 10:05:06 +02:00
subject: Magisk,
id: Int
) = when (val conf = subject.configuration) {
2019-08-22 21:05:41 +02:00
Uninstall -> FlashActivity.uninstall(this, subject.file, id)
is Patch -> FlashActivity.patch(this, subject.file, conf.fileUri, id)
is Flash -> FlashActivity.flash(this, subject.file, conf is Secondary, id)
2019-07-23 10:31:59 +02:00
else -> Unit
}
private fun onFinishedInternal(
2019-07-25 10:05:06 +02:00
subject: Module,
id: Int
) = when (subject.configuration) {
2019-08-22 21:05:41 +02:00
is Flash -> FlashActivity.install(this, subject.file, id)
else -> Unit
}
private fun onFinishedInternal(
subject: Manager,
id: Int
) {
remove(id)
when (subject.configuration) {
2019-10-16 11:07:29 +02:00
is APK.Upgrade -> {
if (isRunningAsStub) {
subject.file.renameTo(DynAPK.update(this))
ProcessPhoenix.triggerRebirth(this)
} else {
APKInstall.install(this, subject.file)
}
}
is APK.Restore -> Unit
}
}
// ---
2019-08-22 21:05:41 +02:00
override fun NotificationCompat.Builder.addActions(subject: DownloadSubject)
= when (subject) {
is Magisk -> addActionsInternal(subject)
is Module -> addActionsInternal(subject)
is Manager -> addActionsInternal(subject)
}
2019-08-22 21:05:41 +02:00
private fun NotificationCompat.Builder.addActionsInternal(subject: Magisk)
= when (val conf = subject.configuration) {
Download -> this.apply {
fileIntent(subject.file.parentFile!!)
.takeIf { it.exists(get()) }
?.let { addAction(0, R.string.download_open_parent, it.chooser()) }
fileIntent(subject.file)
.takeIf { it.exists(get()) }
?.let { addAction(0, R.string.download_open_self, it.chooser()) }
}
2019-08-22 21:05:41 +02:00
Uninstall -> setContentIntent(FlashActivity.uninstallIntent(context, subject.file))
is Flash -> setContentIntent(FlashActivity.flashIntent(context, subject.file, conf is Secondary))
is Patch -> setContentIntent(FlashActivity.patchIntent(context, subject.file, conf.fileUri))
else -> this
}
2019-08-22 21:05:41 +02:00
private fun NotificationCompat.Builder.addActionsInternal(subject: Module)
= when (subject.configuration) {
Download -> this.apply {
fileIntent(subject.file.parentFile!!)
.takeIf { it.exists(get()) }
?.let { addAction(0, R.string.download_open_parent, it.chooser()) }
fileIntent(subject.file)
.takeIf { it.exists(get()) }
?.let { addAction(0, R.string.download_open_self, it.chooser()) }
}
2019-08-22 21:05:41 +02:00
is Flash -> setContentIntent(FlashActivity.installIntent(context, subject.file))
else -> this
}
2019-08-22 21:05:41 +02:00
private fun NotificationCompat.Builder.addActionsInternal(subject: Manager)
= when (subject.configuration) {
APK.Upgrade -> setContentIntent(APKInstall.installIntent(context, subject.file))
else -> this
}
@Suppress("ReplaceSingleLineLet")
private fun NotificationCompat.Builder.setContentIntent(intent: Intent) =
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
.let { setContentIntent(it) }
@Suppress("ReplaceSingleLineLet")
private fun NotificationCompat.Builder.addAction(icon: Int, title: Int, intent: Intent) =
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
.let { addAction(icon, getString(title), it) }
// ---
private fun fileIntent(file: File): Intent {
return Intent(Intent.ACTION_VIEW)
.setDataAndType(file.provide(this), file.type)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
class Builder {
lateinit var subject: DownloadSubject
}
companion object {
inline operator fun invoke(context: Context, argBuilder: Builder.() -> Unit) {
val app = context.applicationContext
val builder = Builder().apply(argBuilder)
2019-10-16 10:38:31 +02:00
val intent = app.intent(DownloadService::class.java).putExtra(ARG_URL, builder.subject)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
app.startForegroundService(intent)
} else {
app.startService(intent)
}
}
}
}