diff --git a/app/src/main/java/com/topjohnwu/magisk/Const.kt b/app/src/main/java/com/topjohnwu/magisk/Const.kt index 826a4fa26..99681169c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Const.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Const.kt @@ -82,6 +82,7 @@ object Const { const val INTENT_SET_NAME = "filename" const val INTENT_SET_LINK = "link" const val FLASH_ACTION = "action" + const val FLASH_DATA = "additional_data" const val BROADCAST_MANAGER_UPDATE = "manager_update" const val BROADCAST_REBOOT = "reboot" } diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt index 1b2d86e94..b76c897f0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt @@ -20,6 +20,8 @@ val viewModelModules = module { viewModel { HideViewModel(get(), get()) } viewModel { ModuleViewModel(get(), get(), get()) } viewModel { LogViewModel(get(), get()) } - viewModel { (action: String, uri: Uri?) -> FlashViewModel(action, uri, get()) } + viewModel { (action: String, file: Uri, additional: Uri) -> + FlashViewModel(action, file, additional, get()) + } viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/CompoundDownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/CompoundDownloadService.kt index 24fe6efd0..2da779832 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/CompoundDownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/CompoundDownloadService.kt @@ -25,8 +25,11 @@ open class CompoundDownloadService : SubstrateDownloadService() { private fun onFinishedInternal( file: File, subject: DownloadSubject.Magisk - ) = when (subject.configuration) { + ) = when (val conf = subject.configuration) { + Configuration.Download -> moveToDownloads(file) Configuration.Flash -> FlashActivity.flash(this, file) + Configuration.Uninstall -> FlashActivity.uninstall(this, file) + is Configuration.Patch -> FlashActivity.patch(this, file, conf.fileUri) else -> Unit } @@ -34,6 +37,7 @@ open class CompoundDownloadService : SubstrateDownloadService() { file: File, subject: DownloadSubject.Module ) = when (subject.configuration) { + Configuration.Download -> moveToDownloads(file) Configuration.Flash -> FlashActivity.install(this, file) else -> Unit } @@ -51,8 +55,12 @@ open class CompoundDownloadService : SubstrateDownloadService() { private fun NotificationCompat.Builder.addActionsInternal( file: File, subject: DownloadSubject.Magisk - ) = when (subject.configuration) { + ) = when (val conf = subject.configuration) { + Configuration.Download -> setContentIntent(fileIntent(subject.fileName)) Configuration.Flash -> setContentIntent(FlashActivity.flashIntent(context, file)) + Configuration.Uninstall -> setContentIntent(FlashActivity.uninstallIntent(context, file)) + is Configuration.Patch -> + setContentIntent(FlashActivity.patchIntent(context, file, conf.fileUri)) else -> this } @@ -60,6 +68,7 @@ open class CompoundDownloadService : SubstrateDownloadService() { file: File, subject: DownloadSubject.Module ) = when (subject.configuration) { + Configuration.Download -> setContentIntent(fileIntent(subject.fileName)) Configuration.Flash -> setContentIntent(FlashActivity.installIntent(context, file)) else -> this } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/SubstrateDownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/SubstrateDownloadService.kt index ac6afec4b..66406da70 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/SubstrateDownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/SubstrateDownloadService.kt @@ -4,14 +4,18 @@ import android.app.NotificationManager import android.app.Service import android.content.Intent import android.os.IBinder +import android.webkit.MimeTypeMap +import android.widget.Toast import androidx.core.app.NotificationCompat import androidx.core.content.getSystemService +import androidx.core.net.toUri import com.skoumal.teanity.extensions.subscribeK import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.R import com.topjohnwu.magisk.data.repository.FileRepository import com.topjohnwu.magisk.model.entity.internal.DownloadSubject +import com.topjohnwu.magisk.utils.toast import com.topjohnwu.magisk.utils.writeToCachedFile import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.superuser.ShellUtils @@ -80,6 +84,27 @@ abstract class SubstrateDownloadService : Service() { // --- + protected fun fileIntent(fileName: String): Intent { + val file = downloadsFile(fileName) + return Intent(Intent.ACTION_VIEW) + .setDataAndType(file.toUri(), file.type) + } + + protected fun moveToDownloads(file: File) { + val destination = downloadsFile(file.name) + file.copyTo(destination) + toast(getString(R.string.internal_storage, "/Download/${file.name}"), Toast.LENGTH_LONG) + } + + // --- + + private val File.type + get() = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension(extension) + .orEmpty() + + private fun downloadsFile(name: String) = File(Const.EXTERNAL_PATH, name) + private fun ResponseBody.toFile(name: String): File { val maxRaw = contentLength() val max = maxRaw / 1_000_000f diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt index bb138c72b..31be1bc54 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashActivity.kt @@ -2,6 +2,7 @@ package com.topjohnwu.magisk.ui.flash import android.content.Context import android.content.Intent +import android.net.Uri import androidx.core.net.toUri import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.Const @@ -16,9 +17,10 @@ open class FlashActivity : MagiskActivity( override val layoutRes: Int = R.layout.activity_flash override val viewModel: FlashViewModel by viewModel { - val uri = intent.data + val uri = intent.data ?: let { finish(); Uri.EMPTY } + val additionalUri = intent.getParcelableExtra(Const.Key.FLASH_DATA) ?: Uri.EMPTY val action = intent.getStringExtra(Const.Key.FLASH_ACTION) ?: let { finish();"" } - parametersOf(action, uri) + parametersOf(action, uri, additionalUri) } override fun onBackPressed() { @@ -41,11 +43,12 @@ open class FlashActivity : MagiskActivity( /* Patching is understood as injecting img files with magisk */ - fun patchIntent(context: Context, file: File) = intent(context, file) + fun patchIntent(context: Context, file: File, uri: Uri) = intent(context, file) + .putExtra(Const.Key.FLASH_DATA, uri) .putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_FILE) - fun patch(context: Context, file: File) = - context.startActivity(patchIntent(context, file)) + fun patch(context: Context, file: File, uri: Uri) = + context.startActivity(patchIntent(context, file, uri)) /* Uninstalling is understood as removing magisk entirely */ diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt index 37a096f7d..46d0533ed 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt @@ -28,7 +28,8 @@ import java.util.* class FlashViewModel( action: String, - uri: Uri?, // FIXME uri is now flashable file, not additional file + file: Uri, + uri: Uri, private val resources: Resources ) : MagiskViewModel(), FlashResultListener { @@ -52,7 +53,6 @@ class FlashViewModel( state = State.LOADING - val uri = uri ?: Uri.EMPTY when (action) { Const.Value.FLASH_ZIP -> Flashing .Install(uri, outItems, logItems, this) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt b/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt index 97acddf5f..b3c7ba5a2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt @@ -9,6 +9,7 @@ import android.content.pm.PackageManager import android.content.pm.PackageManager.* import android.net.Uri import android.provider.OpenableColumns +import android.widget.Toast import com.topjohnwu.magisk.App import java.io.File import java.io.FileNotFoundException @@ -50,21 +51,22 @@ val ApplicationInfo.packageInfo: PackageInfo? } } -val Uri.fileName: String get() { - var name: String? = null - App.self.contentResolver.query(this, null, null, null, null)?.use { c -> - val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME) - if (nameIndex != -1) { - c.moveToFirst() - name = c.getString(nameIndex) +val Uri.fileName: String + get() { + var name: String? = null + App.self.contentResolver.query(this, null, null, null, null)?.use { c -> + val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME) + if (nameIndex != -1) { + c.moveToFirst() + name = c.getString(nameIndex) + } } + if (name == null && path != null) { + val idx = path!!.lastIndexOf('/') + name = path!!.substring(idx + 1) + } + return name.orEmpty() } - if (name == null && path != null) { - val idx = path!!.lastIndexOf('/') - name = path!!.substring(idx + 1) - } - return name.orEmpty() -} fun PackageManager.activities(packageName: String) = getPackageInfo(packageName, GET_ACTIVITIES) @@ -80,10 +82,11 @@ fun PackageManager.providers(packageName: String) = fun Context.rawResource(id: Int) = resources.openRawResource(id) -fun Context.readUri(uri: Uri) = contentResolver.openInputStream(uri) ?: throw FileNotFoundException() +fun Context.readUri(uri: Uri) = + contentResolver.openInputStream(uri) ?: throw FileNotFoundException() fun ApplicationInfo.findAppLabel(pm: PackageManager): String { - return pm.getApplicationLabel(this)?.toString().orEmpty() + return pm.getApplicationLabel(this).toString().orEmpty() } fun Intent.startActivity(context: Context) = context.startActivity(this) @@ -100,4 +103,10 @@ fun File.mv(destination: File) { fun String.toFile() = File(this) -fun Intent.chooser(title: String = "Pick an app") = Intent.createChooser(this, title) \ No newline at end of file +fun Intent.chooser(title: String = "Pick an app") = Intent.createChooser(this, title) + +fun Context.toast(message: Int, duration: Int = Toast.LENGTH_SHORT) = + toast(getString(message), duration) + +fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) = + Toast.makeText(this, message, duration) \ No newline at end of file