mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-30 21:45:27 +00:00
Also download to external storage
This commit is contained in:
parent
2a5f5b1bba
commit
eaf4d8064b
@ -8,10 +8,8 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.ForegroundTracker
|
import com.topjohnwu.magisk.core.ForegroundTracker
|
||||||
import com.topjohnwu.magisk.core.base.BaseService
|
import com.topjohnwu.magisk.core.base.BaseService
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
|
||||||
import com.topjohnwu.magisk.core.utils.ProgressInputStream
|
import com.topjohnwu.magisk.core.utils.ProgressInputStream
|
||||||
import com.topjohnwu.magisk.data.repository.NetworkService
|
import com.topjohnwu.magisk.data.repository.NetworkService
|
||||||
import com.topjohnwu.magisk.ktx.withStreams
|
|
||||||
import com.topjohnwu.magisk.view.Notifications
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -72,11 +70,7 @@ abstract class BaseDownloader : BaseService(), KoinComponent {
|
|||||||
when (this) {
|
when (this) {
|
||||||
is Subject.Module -> // Download and process on-the-fly
|
is Subject.Module -> // Download and process on-the-fly
|
||||||
stream.toModule(file, service.fetchInstaller().byteStream())
|
stream.toModule(file, service.fetchInstaller().byteStream())
|
||||||
else -> {
|
is Subject.Manager -> handleAPK(this, stream)
|
||||||
withStreams(stream, file.outputStream()) { it, out -> it.copyTo(out) }
|
|
||||||
if (this is Subject.Manager)
|
|
||||||
handleAPK(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val newId = notifyFinish(this)
|
val newId = notifyFinish(this)
|
||||||
if (ForegroundTracker.hasForeground)
|
if (ForegroundTracker.hasForeground)
|
||||||
|
@ -7,9 +7,13 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||||
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||||
import com.topjohnwu.magisk.ktx.relaunchApp
|
import com.topjohnwu.magisk.ktx.relaunchApp
|
||||||
|
import com.topjohnwu.magisk.ktx.withStreams
|
||||||
import com.topjohnwu.magisk.ktx.writeTo
|
import com.topjohnwu.magisk.ktx.writeTo
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
private fun Context.patch(apk: File) {
|
private fun Context.patch(apk: File) {
|
||||||
val patched = File(apk.parent, "patched.apk")
|
val patched = File(apk.parent, "patched.apk")
|
||||||
@ -26,17 +30,38 @@ private fun BaseDownloader.notifyHide(id: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun BaseDownloader.handleAPK(subject: Subject.Manager) {
|
private class DupOutputStream(
|
||||||
if (!isRunningAsStub)
|
private val o1: OutputStream,
|
||||||
return
|
private val o2: OutputStream
|
||||||
|
) : OutputStream() {
|
||||||
|
override fun write(b: Int) {
|
||||||
|
o1.write(b)
|
||||||
|
o2.write(b)
|
||||||
|
}
|
||||||
|
override fun write(b: ByteArray?, off: Int, len: Int) {
|
||||||
|
o1.write(b, off, len)
|
||||||
|
o2.write(b, off, len)
|
||||||
|
}
|
||||||
|
override fun close() {
|
||||||
|
o1.close()
|
||||||
|
o2.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun BaseDownloader.handleAPK(subject: Subject.Manager, stream: InputStream) {
|
||||||
|
fun write(output: OutputStream) {
|
||||||
|
val ext = subject.externalFile.outputStream()
|
||||||
|
val o = DupOutputStream(ext, output)
|
||||||
|
withStreams(stream, o) { src, out -> src.copyTo(out) }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRunningAsStub) {
|
||||||
val apk = subject.file.toFile()
|
val apk = subject.file.toFile()
|
||||||
val id = subject.notifyID()
|
val id = subject.notifyID()
|
||||||
// Move to upgrade location
|
write(DynAPK.update(this).outputStream())
|
||||||
apk.copyTo(DynAPK.update(this), overwrite = true)
|
|
||||||
apk.delete()
|
|
||||||
if (Info.stub!!.version < subject.stub.versionCode) {
|
if (Info.stub!!.version < subject.stub.versionCode) {
|
||||||
notifyHide(id)
|
|
||||||
// Also upgrade stub
|
// Also upgrade stub
|
||||||
|
notifyHide(id)
|
||||||
service.fetchFile(subject.stub.link).byteStream().writeTo(apk)
|
service.fetchFile(subject.stub.link).byteStream().writeTo(apk)
|
||||||
patch(apk)
|
patch(apk)
|
||||||
} else {
|
} else {
|
||||||
@ -44,4 +69,7 @@ suspend fun BaseDownloader.handleAPK(subject: Subject.Manager) {
|
|||||||
stopSelf()
|
stopSelf()
|
||||||
relaunchApp(this)
|
relaunchApp(this)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
write(subject.file.outputStream())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package com.topjohnwu.magisk.core.download
|
package com.topjohnwu.magisk.core.download
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.topjohnwu.magisk.ktx.withStreams
|
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||||
|
import com.topjohnwu.magisk.ktx.forEach
|
||||||
|
import com.topjohnwu.magisk.ktx.withStreams
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
@ -25,8 +26,7 @@ fun InputStream.toModule(file: Uri, installer: InputStream) {
|
|||||||
zout.write("#MAGISK\n".toByteArray(charset("UTF-8")))
|
zout.write("#MAGISK\n".toByteArray(charset("UTF-8")))
|
||||||
|
|
||||||
var off = -1
|
var off = -1
|
||||||
var entry: ZipEntry? = zin.nextEntry
|
zin.forEach { entry ->
|
||||||
while (entry != null) {
|
|
||||||
if (off < 0) {
|
if (off < 0) {
|
||||||
off = entry.name.indexOf('/') + 1
|
off = entry.name.indexOf('/') + 1
|
||||||
}
|
}
|
||||||
@ -38,8 +38,6 @@ fun InputStream.toModule(file: Uri, installer: InputStream) {
|
|||||||
zin.copyTo(zout)
|
zin.copyTo(zout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = zin.nextEntry
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ sealed class Subject : Parcelable {
|
|||||||
cachedFile("manager.apk")
|
cachedFile("manager.apk")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val externalFile get() = MediaStoreUtils.getFile("$title.apk").uri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import java.util.*
|
|||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) {
|
inline fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) {
|
||||||
var entry: ZipEntry? = nextEntry
|
var entry: ZipEntry? = nextEntry
|
||||||
while (entry != null) {
|
while (entry != null) {
|
||||||
callback(entry)
|
callback(entry)
|
||||||
|
@ -114,7 +114,7 @@ class HomeViewModel(
|
|||||||
fun onDeletePressed() = UninstallDialog().publish()
|
fun onDeletePressed() = UninstallDialog().publish()
|
||||||
|
|
||||||
fun onManagerPressed() = when (state) {
|
fun onManagerPressed() = when (state) {
|
||||||
State.LOADED -> ManagerInstallDialog().publish()
|
State.LOADED -> withExternalRW { ManagerInstallDialog().publish() }
|
||||||
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
||||||
else -> SnackbarEvent(R.string.no_connection).publish()
|
else -> SnackbarEvent(R.string.no_connection).publish()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user