diff --git a/app/src/main/java/com/aurora/Constants.kt b/app/src/main/java/com/aurora/Constants.kt index 66763e14a..9ff8c1739 100644 --- a/app/src/main/java/com/aurora/Constants.kt +++ b/app/src/main/java/com/aurora/Constants.kt @@ -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" diff --git a/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt b/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt index 6c70f321e..7630a834d 100644 --- a/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt +++ b/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt @@ -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() diff --git a/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt index f1bf1da2f..bdb37bc98 100644 --- a/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt @@ -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) { - 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, diff --git a/app/src/main/java/com/aurora/store/data/installer/IInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/IInstaller.kt index 141737eda..d0b9200bb 100644 --- a/app/src/main/java/com/aurora/store/data/installer/IInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/IInstaller.kt @@ -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) + fun install(download: Download) fun clearQueue() fun isAlreadyQueued(packageName: String): Boolean fun removeFromInstallQueue(packageName: String) diff --git a/app/src/main/java/com/aurora/store/data/installer/InstallerBase.kt b/app/src/main/java/com/aurora/store/data/installer/InstallerBase.kt index de5846fd0..fe505cd96 100644 --- a/app/src/main/java/com/aurora/store/data/installer/InstallerBase.kt +++ b/app/src/main/java/com/aurora/store/data/installer/InstallerBase.kt @@ -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 { + 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, diff --git a/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt index 9253dfd03..b86768b2e 100644 --- a/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt @@ -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) { - 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) } } } diff --git a/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt index e4e59aa5f..7c320edcf 100644 --- a/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt @@ -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) { - 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) ) diff --git a/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt index 49e721389..7ea552d5a 100644 --- a/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt @@ -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) { + 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) ) diff --git a/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt index 78a07529b..c736e1f52 100644 --- a/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt @@ -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() - override fun install(packageName: String, files: List) { - 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) + ) } } } diff --git a/app/src/main/java/com/aurora/store/data/installer/SessionInstallerBase.kt b/app/src/main/java/com/aurora/store/data/installer/SessionInstallerBase.kt index d35e4ba95..7c351dd48 100644 --- a/app/src/main/java/com/aurora/store/data/installer/SessionInstallerBase.kt +++ b/app/src/main/java/com/aurora/store/data/installer/SessionInstallerBase.kt @@ -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 + files: List ) { - 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 - } } diff --git a/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt index 88c05d0a7..ae5553703 100644 --- a/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt @@ -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) { - 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) + ) } } } diff --git a/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt b/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt index 2adbb29ed..9a5ef1e55 100644 --- a/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt @@ -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) } diff --git a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt index 59e2514da..97612d03c 100644 --- a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt +++ b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt @@ -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 ) } } diff --git a/app/src/main/java/com/aurora/store/view/ui/sheets/DownloadMenuSheet.kt b/app/src/main/java/com/aurora/store/view/ui/sheets/DownloadMenuSheet.kt index 9cb5f9f58..816e24103 100644 --- a/app/src/main/java/com/aurora/store/view/ui/sheets/DownloadMenuSheet.kt +++ b/app/src/main/java/com/aurora/store/view/ui/sheets/DownloadMenuSheet.kt @@ -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) {