forked from MarcoBuster/Magisk
164 lines
6.0 KiB
Kotlin
164 lines
6.0 KiB
Kotlin
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
|
|
import com.topjohnwu.magisk.ProcessPhoenix
|
|
import com.topjohnwu.magisk.R
|
|
import com.topjohnwu.magisk.extensions.chooser
|
|
import com.topjohnwu.magisk.extensions.exists
|
|
import com.topjohnwu.magisk.extensions.provide
|
|
import com.topjohnwu.magisk.intent
|
|
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
|
|
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"
|
|
|
|
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(
|
|
subject: Magisk,
|
|
id: Int
|
|
) = when (val conf = subject.configuration) {
|
|
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)
|
|
else -> Unit
|
|
}
|
|
|
|
private fun onFinishedInternal(
|
|
subject: Module,
|
|
id: Int
|
|
) = when (subject.configuration) {
|
|
is Flash -> FlashActivity.install(this, subject.file, id)
|
|
else -> Unit
|
|
}
|
|
|
|
private fun onFinishedInternal(
|
|
subject: Manager,
|
|
id: Int
|
|
) {
|
|
remove(id)
|
|
when (subject.configuration) {
|
|
is APK.Upgrade -> {
|
|
if (isRunningAsStub) {
|
|
subject.file.renameTo(DynAPK.update(this))
|
|
ProcessPhoenix.triggerRebirth(this)
|
|
} else {
|
|
APKInstall.install(this, subject.file)
|
|
}
|
|
}
|
|
is APK.Restore -> Unit
|
|
}
|
|
}
|
|
|
|
// ---
|
|
|
|
override fun NotificationCompat.Builder.addActions(subject: DownloadSubject)
|
|
= when (subject) {
|
|
is Magisk -> addActionsInternal(subject)
|
|
is Module -> addActionsInternal(subject)
|
|
is Manager -> addActionsInternal(subject)
|
|
}
|
|
|
|
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()) }
|
|
}
|
|
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
|
|
}
|
|
|
|
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()) }
|
|
}
|
|
is Flash -> setContentIntent(FlashActivity.installIntent(context, subject.file))
|
|
else -> this
|
|
}
|
|
|
|
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)
|
|
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)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} |