IInstaller: Use Download object for installing apps
Contains all required data for us to install an app making things easier to work with. Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -24,6 +24,7 @@ object Constants {
|
||||
const val FLOAT_EXTRA = "FLOAT_EXTRA"
|
||||
const val STRING_APP = "STRING_APP"
|
||||
const val STRING_VERSION = "STRING_VERSION"
|
||||
const val PARCEL_DOWNLOAD = "PARCEL_DOWNLOAD"
|
||||
const val STRING_EXTRA = "STRING_EXTRA"
|
||||
const val BROWSE_EXTRA = "BROWSE_EXTRA"
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ import android.content.pm.PackageInstaller
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.IntentCompat
|
||||
import com.aurora.Constants
|
||||
import com.aurora.store.data.installer.SessionInstaller
|
||||
import com.aurora.store.util.PathUtil
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -19,9 +20,10 @@ class InstallActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val packageName = intent.extras?.getString(Constants.STRING_APP) ?: String()
|
||||
val versionCode = intent.extras?.getInt(Constants.STRING_VERSION)
|
||||
if (packageName.isNotBlank() && versionCode != null) {
|
||||
val download =
|
||||
IntentCompat.getParcelableExtra(intent, Constants.PARCEL_DOWNLOAD, Download::class.java)
|
||||
|
||||
if (download != null) {
|
||||
val callback = object : PackageInstaller.SessionCallback() {
|
||||
override fun onCreated(sessionId: Int) {}
|
||||
|
||||
@@ -39,15 +41,14 @@ class InstallActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
packageManager.packageInstaller.registerSessionCallback(callback)
|
||||
install(packageName, versionCode)
|
||||
install(download)
|
||||
}
|
||||
}
|
||||
|
||||
private fun install(packageName: String, versionCode: Int) {
|
||||
private fun install(download: Download) {
|
||||
sessionInstaller = SessionInstaller(this)
|
||||
try {
|
||||
val files = PathUtil.getAppDownloadDir(this, packageName, versionCode).listFiles()
|
||||
sessionInstaller.install(packageName, files!!.filter { it.path.endsWith(".apk") })
|
||||
sessionInstaller.install(download)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to install $packageName")
|
||||
finish()
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.aurora.store.data.installer
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.content.FileProvider
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.util.Log
|
||||
import java.io.*
|
||||
import java.util.zip.ZipEntry
|
||||
@@ -14,20 +15,13 @@ class AMInstaller(context: Context) : InstallerBase(context) {
|
||||
const val AM_DEBUG_PACKAGE_NAME = "io.github.muntashirakon.AppManager.debug"
|
||||
}
|
||||
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
override fun install(download: Download) {
|
||||
if (isAlreadyQueued(download.packageName)) {
|
||||
Log.i("${download.packageName} already queued")
|
||||
} else {
|
||||
Log.i("Received AM install request for $packageName")
|
||||
val fileList = files.map {
|
||||
when (it) {
|
||||
is File -> it.absolutePath
|
||||
is String -> File(it).absolutePath
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.i("Received AM install request for ${download.packageName}")
|
||||
val fileList =
|
||||
getFiles(download.packageName, download.versionCode).map { it.absolutePath }
|
||||
when {
|
||||
fileList.size == 1 -> {
|
||||
xInstall(File(fileList.first()))
|
||||
@@ -44,7 +38,7 @@ class AMInstaller(context: Context) : InstallerBase(context) {
|
||||
}
|
||||
|
||||
private fun xInstall(file: File) {
|
||||
val intent: Intent = Intent(Intent.ACTION_VIEW)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(
|
||||
FileProvider.getUriForFile(
|
||||
context,
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
package com.aurora.store.data.installer
|
||||
|
||||
import com.aurora.store.data.room.download.Download
|
||||
|
||||
interface IInstaller {
|
||||
fun install(packageName: String, files: List<Any>)
|
||||
fun install(download: Download)
|
||||
fun clearQueue()
|
||||
fun isAlreadyQueued(packageName: String): Boolean
|
||||
fun removeFromInstallQueue(packageName: String)
|
||||
|
||||
@@ -25,7 +25,9 @@ import androidx.core.content.FileProvider
|
||||
import com.aurora.store.AuroraApplication
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.PathUtil
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.io.File
|
||||
|
||||
@@ -55,6 +57,15 @@ abstract class InstallerBase(protected var context: Context) : IInstaller {
|
||||
EventBus.getDefault().post(event)
|
||||
}
|
||||
|
||||
open fun getFiles(packageName: String, versionCode: Int, sharedLibPackageName: String = ""): List<File> {
|
||||
val downloadDir = if (sharedLibPackageName.isNotBlank()) {
|
||||
PathUtil.getLibDownloadDir(context, packageName, versionCode, sharedLibPackageName)
|
||||
} else {
|
||||
PathUtil.getAppDownloadDir(context, packageName, versionCode)
|
||||
}
|
||||
return downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
||||
}
|
||||
|
||||
open fun getUri(file: File): Uri {
|
||||
return FileProvider.getUriForFile(
|
||||
context,
|
||||
|
||||
@@ -23,28 +23,19 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.util.Log
|
||||
import java.io.File
|
||||
|
||||
@Deprecated("Deprecated in favour of SessionInstaller")
|
||||
class NativeInstaller(context: Context) : InstallerBase(context) {
|
||||
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
override fun install(download: Download) {
|
||||
if (isAlreadyQueued(download.packageName)) {
|
||||
Log.i("${download.packageName} already queued")
|
||||
} else {
|
||||
Log.i("Received native install request for $packageName")
|
||||
files.map {
|
||||
when (it) {
|
||||
is File -> it
|
||||
is String -> File(it)
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}.forEach {
|
||||
xInstall(it)
|
||||
}
|
||||
Log.i("Received native install request for ${download.packageName}")
|
||||
getFiles(download.packageName, download.versionCode).forEach { xInstall(it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ package com.aurora.store.data.installer
|
||||
import android.content.Context
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.util.Log
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
@@ -30,25 +31,15 @@ import java.util.regex.Pattern
|
||||
|
||||
class RootInstaller(context: Context) : InstallerBase(context) {
|
||||
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
override fun install(download: Download) {
|
||||
if (isAlreadyQueued(download.packageName)) {
|
||||
Log.i("${download.packageName} already queued")
|
||||
} else {
|
||||
if (Shell.getShell().isRoot) {
|
||||
files.map {
|
||||
when (it) {
|
||||
is File -> it
|
||||
is String -> File(it)
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}.let {
|
||||
xInstall(packageName, it)
|
||||
}
|
||||
xInstall(download.packageName, getFiles(download.packageName, download.versionCode))
|
||||
} else {
|
||||
postError(
|
||||
packageName,
|
||||
download.packageName,
|
||||
context.getString(R.string.installer_status_failure),
|
||||
context.getString(R.string.installer_root_unavailable)
|
||||
)
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.event.BusEvent
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
@@ -58,39 +59,25 @@ class ServiceInstaller(context: Context) : InstallerBase(context) {
|
||||
const val PRIVILEGED_EXTENSION_SERVICE_INTENT = "com.aurora.services.IPrivilegedService"
|
||||
}
|
||||
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
override fun install(download: Download) {
|
||||
|
||||
when {
|
||||
isAlreadyQueued(packageName) -> {
|
||||
Log.i("$packageName already queued")
|
||||
isAlreadyQueued(download.packageName) -> {
|
||||
Log.i("${download.packageName} already queued")
|
||||
}
|
||||
|
||||
PackageUtil.isInstalled(context, PRIVILEGED_EXTENSION_PACKAGE_NAME) -> {
|
||||
Log.i("Received service install request for $packageName")
|
||||
val uriList = files.map {
|
||||
when (it) {
|
||||
is File -> getUri(it)
|
||||
is String -> getUri(File(it))
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}
|
||||
val fileList = files.map {
|
||||
when (it) {
|
||||
is File -> it.absolutePath
|
||||
is String -> File(it).absolutePath
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xInstall(packageName, uriList, fileList)
|
||||
Log.i("Received service install request for ${download.packageName}")
|
||||
val fileList = getFiles(download.packageName, download.versionCode)
|
||||
xInstall(
|
||||
download.packageName,
|
||||
fileList.map { getUri(it) },
|
||||
fileList.map { it.absolutePath }
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
postError(
|
||||
packageName,
|
||||
download.packageName,
|
||||
context.getString(R.string.installer_status_failure),
|
||||
context.getString(R.string.installer_service_unavailable)
|
||||
)
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.aurora.extensions.isOAndAbove
|
||||
import com.aurora.extensions.isSAndAbove
|
||||
import com.aurora.extensions.isTAndAbove
|
||||
import com.aurora.extensions.isUAndAbove
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.util.Log
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@@ -37,15 +38,15 @@ class SessionInstaller(context: Context) : SessionInstallerBase(context) {
|
||||
|
||||
var sessionId by Delegates.notNull<Int>()
|
||||
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
override fun install(download: Download) {
|
||||
if (isAlreadyQueued(download.packageName)) {
|
||||
Log.i("${download.packageName} already queued")
|
||||
} else {
|
||||
Log.i("Received session install request for $packageName")
|
||||
Log.i("Received session install request for ${download.packageName}")
|
||||
|
||||
val packageInstaller = context.packageManager.packageInstaller
|
||||
val sessionParams = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
|
||||
setAppPackageName(packageName)
|
||||
setAppPackageName(download.packageName)
|
||||
if (isOAndAbove()) {
|
||||
setInstallReason(PackageManager.INSTALL_REASON_USER)
|
||||
}
|
||||
@@ -66,7 +67,12 @@ class SessionInstaller(context: Context) : SessionInstallerBase(context) {
|
||||
sessionId = packageInstaller.createSession(sessionParams)
|
||||
val session = packageInstaller.openSession(sessionId)
|
||||
|
||||
xInstall(sessionId, session, packageName, files)
|
||||
xInstall(
|
||||
sessionId,
|
||||
session,
|
||||
download.packageName,
|
||||
getFiles(download.packageName, download.versionCode)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,7 @@ import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.net.Uri
|
||||
import androidx.core.content.FileProvider
|
||||
import com.aurora.extensions.isSAndAbove
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.receiver.InstallerStatusReceiver
|
||||
import com.aurora.store.util.Log
|
||||
import java.io.File
|
||||
@@ -38,26 +35,17 @@ abstract class SessionInstallerBase(context: Context) : InstallerBase(context) {
|
||||
sessionId: Int,
|
||||
session: PackageInstaller.Session,
|
||||
packageName: String,
|
||||
files: List<Any>
|
||||
files: List<File>
|
||||
) {
|
||||
val uriList = files.map {
|
||||
when (it) {
|
||||
is File -> getUri(it)
|
||||
is String -> getUri(File(it))
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Log.i("Writing splits to session for $packageName")
|
||||
|
||||
for (uri in uriList) {
|
||||
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||
session.openWrite("${packageName}_${System.currentTimeMillis()}", 0, -1).use {
|
||||
input.copyTo(it)
|
||||
session.fsync(it)
|
||||
files.forEach {
|
||||
it.inputStream().use { input ->
|
||||
session.openWrite("${packageName}_${System.currentTimeMillis()}", 0, -1).use { output ->
|
||||
input.copyTo(output)
|
||||
session.fsync(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,20 +81,4 @@ abstract class SessionInstallerBase(context: Context) : InstallerBase(context) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUri(file: File): Uri {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${BuildConfig.APPLICATION_ID}.fileProvider",
|
||||
file
|
||||
)
|
||||
|
||||
context.grantUriPermission(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
|
||||
return uri
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ import androidx.annotation.RequiresApi
|
||||
import com.aurora.extensions.isOAndAbove
|
||||
import com.aurora.extensions.isSAndAbove
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.util.Log
|
||||
import dev.rikka.tools.refine.Refine
|
||||
import rikka.shizuku.ShizukuBinderWrapper
|
||||
import rikka.shizuku.SystemServiceHelper
|
||||
|
||||
|
||||
class ShizukuInstaller(context: Context) : SessionInstallerBase(context) {
|
||||
|
||||
companion object {
|
||||
@@ -66,11 +66,11 @@ class ShizukuInstaller(context: Context) : SessionInstallerBase(context) {
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun install(packageName: String, files: List<Any>) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
override fun install(download: Download) {
|
||||
if (isAlreadyQueued(download.packageName)) {
|
||||
Log.i("${download.packageName} already queued")
|
||||
} else {
|
||||
Log.i("Received session install request for $packageName")
|
||||
Log.i("Received session install request for ${download.packageName}")
|
||||
|
||||
val (sessionId, session) = kotlin.runCatching {
|
||||
val params = SessionParams(SessionParams.MODE_FULL_INSTALL)
|
||||
@@ -94,14 +94,19 @@ class ShizukuInstaller(context: Context) : SessionInstallerBase(context) {
|
||||
}.getOrElse { ex ->
|
||||
ex.printStackTrace()
|
||||
postError(
|
||||
packageName,
|
||||
download.packageName,
|
||||
context.getString(R.string.installer_status_failure),
|
||||
context.getString(R.string.installer_shizuku_unavailable)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
xInstall(sessionId, session, packageName, files)
|
||||
xInstall(
|
||||
sessionId,
|
||||
session,
|
||||
download.packageName,
|
||||
getFiles(download.packageName, download.versionCode)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,13 +161,7 @@ class DownloadWorker @AssistedInject constructor(
|
||||
private suspend fun onSuccess() {
|
||||
withContext(NonCancellable) {
|
||||
try {
|
||||
val downloadDir = PathUtil.getAppDownloadDir(
|
||||
appContext, download.packageName, download.versionCode
|
||||
)
|
||||
appInstaller.getPreferredInstaller().install(
|
||||
download.packageName,
|
||||
downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
||||
)
|
||||
appInstaller.getPreferredInstaller().install(download)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to install ${download.packageName}", exception)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.aurora.store.data.room.download.Download as AuroraDownload
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.activity.InstallActivity
|
||||
import com.aurora.store.data.model.DownloadStatus
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import java.net.URL
|
||||
import java.util.UUID
|
||||
|
||||
@@ -121,7 +122,7 @@ object NotificationUtil {
|
||||
NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_install,
|
||||
context.getString(R.string.action_install),
|
||||
getInstallIntent(context, download.packageName, download.versionCode)
|
||||
getInstallIntent(context, download)
|
||||
).build()
|
||||
)
|
||||
}
|
||||
@@ -207,14 +208,9 @@ object NotificationUtil {
|
||||
.createPendingIntent()
|
||||
}
|
||||
|
||||
private fun getInstallIntent(
|
||||
context: Context,
|
||||
packageName: String,
|
||||
version: Int
|
||||
): PendingIntent {
|
||||
private fun getInstallIntent(context: Context, download: Download): PendingIntent {
|
||||
val intent = Intent(context, InstallActivity::class.java).apply {
|
||||
putExtra(Constants.STRING_APP, packageName)
|
||||
putExtra(Constants.STRING_VERSION, version)
|
||||
putExtra(Constants.PARCEL_DOWNLOAD, download)
|
||||
}
|
||||
val flags = if (isMAndAbove()) {
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
@@ -222,7 +218,7 @@ object NotificationUtil {
|
||||
PendingIntent.FLAG_CANCEL_CURRENT
|
||||
}
|
||||
return PendingIntent.getActivity(
|
||||
context, packageName.hashCode(), intent, flags
|
||||
context, download.packageName.hashCode(), intent, flags
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.model.DownloadStatus
|
||||
import com.aurora.store.databinding.SheetDownloadMenuBinding
|
||||
import com.aurora.store.util.DownloadWorkerUtil
|
||||
import com.aurora.store.util.PathUtil
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
@@ -111,15 +110,7 @@ class DownloadMenuSheet : BaseBottomSheet() {
|
||||
|
||||
private fun install() {
|
||||
try {
|
||||
val downloadDir = PathUtil.getAppDownloadDir(
|
||||
requireContext(),
|
||||
args.download.packageName,
|
||||
args.download.versionCode
|
||||
)
|
||||
appInstaller.getPreferredInstaller().install(
|
||||
args.download.packageName,
|
||||
downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
||||
)
|
||||
appInstaller.getPreferredInstaller().install(args.download)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to install ${args.download.packageName}", exception)
|
||||
if (exception is NullPointerException) {
|
||||
|
||||
Reference in New Issue
Block a user