mirror of
https://github.com/whyorean/AuroraStore.git
synced 2026-06-17 04:00:58 -04:00
DO NOT MERGE: AppInstaller: Rework and extend silent install logic check
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package com.aurora.extensions
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.aurora.store.BuildConfig
|
||||
|
||||
fun PackageManager.getInstallerPackageNameCompat(packageName: String): String? {
|
||||
return if (isRAndAbove()) {
|
||||
@@ -10,3 +13,17 @@ fun PackageManager.getInstallerPackageNameCompat(packageName: String): String? {
|
||||
return getInstallerPackageName(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.S)
|
||||
fun PackageManager.getUpdateOwnerPackageNameCompat(packageName: String): String? {
|
||||
// https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int)
|
||||
val installSourceInfo = getInstallSourceInfo(packageName)
|
||||
return when {
|
||||
isUAndAbove() -> {
|
||||
// If update ownership is null, we can still silently update it if we installed it
|
||||
installSourceInfo.updateOwnerPackageName ?: installSourceInfo.installingPackageName
|
||||
}
|
||||
isSAndAbove() -> installSourceInfo.installingPackageName
|
||||
else -> if (packageName == BuildConfig.APPLICATION_ID) BuildConfig.APPLICATION_ID else null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,17 @@ import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.content.pm.PackageInfoCompat
|
||||
import com.aurora.extensions.getUpdateOwnerPackageNameCompat
|
||||
import com.aurora.extensions.isOAndAbove
|
||||
import com.aurora.extensions.isPAndAbove
|
||||
import com.aurora.extensions.isSAndAbove
|
||||
import com.aurora.extensions.isTAndAbove
|
||||
import com.aurora.extensions.isUAndAbove
|
||||
import com.aurora.extensions.isVAndAbove
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.model.InstallerInfo
|
||||
import com.aurora.store.util.CertUtil
|
||||
import com.aurora.store.util.NotificationUtil
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
@@ -101,6 +108,37 @@ class AppInstaller @Inject constructor(
|
||||
return installers
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given package can be silently installed
|
||||
* @param context [Context]
|
||||
* @param packageName Package to silently install
|
||||
*/
|
||||
fun canInstallSilently(context: Context, packageName: String, targetSdk: Int): Boolean {
|
||||
return when (getCurrentInstaller(context)) {
|
||||
Installer.SESSION -> {
|
||||
// Silent install cannot be done on initial install and below A12
|
||||
if (!PackageUtil.isInstalled(context, packageName) || !isSAndAbove()) return false
|
||||
|
||||
// We cannot do silent updates if we are not the update owner
|
||||
if (context.packageManager.getUpdateOwnerPackageNameCompat(packageName) != BuildConfig.APPLICATION_ID) return false
|
||||
|
||||
// Ensure app being installed satisfies Android's requirement for targetSdk level
|
||||
when (Build.VERSION.SDK_INT) {
|
||||
Build.VERSION_CODES.VANILLA_ICE_CREAM -> targetSdk == Build.VERSION_CODES.TIRAMISU
|
||||
Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> targetSdk == Build.VERSION_CODES.S
|
||||
Build.VERSION_CODES.TIRAMISU -> targetSdk == Build.VERSION_CODES.R
|
||||
Build.VERSION_CODES.S -> targetSdk == Build.VERSION_CODES.Q
|
||||
else -> false // Only Android version above 12 can silently update apps
|
||||
}
|
||||
}
|
||||
Installer.NATIVE -> false // Deprecated
|
||||
Installer.ROOT -> hasRootAccess()
|
||||
Installer.SERVICE -> false // Deprecated
|
||||
Installer.AM -> false // We cannot check if AppManager has ability to auto-update
|
||||
Installer.SHIZUKU -> isOAndAbove() && hasShizukuOrSui(context) && hasShizukuPerm()
|
||||
}
|
||||
}
|
||||
|
||||
fun notifyInstallation(context: Context, displayName: String, packageName: String) {
|
||||
val notificationManager = context.getSystemService<NotificationManager>()
|
||||
val notification = NotificationUtil.getInstallNotification(context, displayName, packageName)
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.aurora.store.data.room.update.UpdateDao
|
||||
|
||||
@Database(
|
||||
entities = [Download::class, Favourite::class, Update::class],
|
||||
version = 3,
|
||||
version = 4,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(DownloadConverter::class)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.aurora.store.data.room
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
/**
|
||||
* A helper class for doing migrations for the [AuroraDatabase].
|
||||
* @see [RoomModule]
|
||||
*/
|
||||
object MigrationHelper {
|
||||
|
||||
// ADD ALL NEW MIGRATION STEPS HERE TOO
|
||||
val MIGRATION_1_4 = object : Migration(1, 4) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
migrateFrom3To4(db)
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_3_4 = object : Migration(3, 4) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) = migrateFrom3To4(db)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add targetSdk column to download and update table for checking if silent install is possible.
|
||||
*/
|
||||
private fun migrateFrom3To4(db: SupportSQLiteDatabase) {
|
||||
db.apply {
|
||||
execSQL("ALTER TABLE download ADD COLUMN targetSdk INTEGER")
|
||||
execSQL("ALTER TABLE update ADD COLUMN targetSdk INTEGER")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.aurora.store.data.room
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import com.aurora.store.data.room.MigrationHelper.MIGRATION_1_4
|
||||
import com.aurora.store.data.room.MigrationHelper.MIGRATION_3_4
|
||||
import com.aurora.store.data.room.download.DownloadConverter
|
||||
import com.aurora.store.data.room.download.DownloadDao
|
||||
import com.aurora.store.data.room.favourites.FavouriteDao
|
||||
@@ -26,6 +28,7 @@ object RoomModule {
|
||||
downloadConverter: DownloadConverter
|
||||
): AuroraDatabase {
|
||||
return Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE)
|
||||
.addMigrations(MIGRATION_3_4, MIGRATION_1_4)
|
||||
.addTypeConverter(downloadConverter)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ data class Download(
|
||||
var totalFiles: Int,
|
||||
var downloadedFiles: Int,
|
||||
var fileList: List<File>,
|
||||
val sharedLibs: List<SharedLib>
|
||||
val sharedLibs: List<SharedLib>,
|
||||
val targetSdk: Int,
|
||||
) : Parcelable {
|
||||
val isFinished get() = downloadStatus in DownloadStatus.finished
|
||||
val isRunning get() = downloadStatus in DownloadStatus.running
|
||||
@@ -50,7 +51,8 @@ data class Download(
|
||||
0,
|
||||
0,
|
||||
app.fileList.filterNot { it.url.isBlank() },
|
||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }
|
||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
|
||||
app.targetSdk
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,7 +73,8 @@ data class Download(
|
||||
0,
|
||||
0,
|
||||
update.fileList,
|
||||
update.sharedLibs
|
||||
update.sharedLibs,
|
||||
update.targetSdk
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ data class Update(
|
||||
val hasValidCert: Boolean,
|
||||
val offerType: Int,
|
||||
var fileList: List<File>,
|
||||
val sharedLibs: List<SharedLib>
|
||||
val sharedLibs: List<SharedLib>,
|
||||
val targetSdk: Int
|
||||
) : Parcelable {
|
||||
|
||||
companion object {
|
||||
@@ -52,7 +53,8 @@ data class Update(
|
||||
},
|
||||
app.offerType,
|
||||
app.fileList.filterNot { it.url.isBlank() },
|
||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }
|
||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
|
||||
app.targetSdk
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,9 @@ import androidx.work.WorkManager
|
||||
import androidx.work.WorkerParameters
|
||||
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
||||
import com.aurora.extensions.isMAndAbove
|
||||
import com.aurora.extensions.isOAndAbove
|
||||
import com.aurora.extensions.isSAndAbove
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.installer.AppInstaller.Companion.Installer
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.util.AppUtil
|
||||
import com.aurora.store.util.CertUtil
|
||||
import com.aurora.store.util.DownloadWorkerUtil
|
||||
import com.aurora.store.util.NotificationUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
@@ -141,7 +137,9 @@ class UpdateWorker @AssistedInject constructor(
|
||||
} else {
|
||||
if (appContext.isIgnoringBatteryOptimizations()) {
|
||||
// Trigger download for apps if they can be auto-updated (if any)
|
||||
updatesList.filter { canAutoUpdate(it.packageName) }.let { list ->
|
||||
updatesList.filter {
|
||||
AppInstaller.canInstallSilently(appContext, it.packageName, it.targetSdk)
|
||||
}.let { list ->
|
||||
if (list.isEmpty()) return@let
|
||||
|
||||
Log.i(TAG, "Found auto-update enabled apps, updating!")
|
||||
@@ -149,7 +147,9 @@ class UpdateWorker @AssistedInject constructor(
|
||||
}
|
||||
|
||||
// Notify about remaining apps (if any)
|
||||
updatesList.filterNot { canAutoUpdate(it.packageName) }.let { list ->
|
||||
updatesList.filterNot {
|
||||
AppInstaller.canInstallSilently(appContext, it.packageName, it.targetSdk)
|
||||
}.let { list ->
|
||||
if (list.isEmpty()) return@let
|
||||
|
||||
Log.i(TAG, "Found apps that cannot be auto-updated, notifying!")
|
||||
@@ -179,19 +179,4 @@ class UpdateWorker @AssistedInject constructor(
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given package can be auto-updated or not
|
||||
*/
|
||||
private fun canAutoUpdate(packageName: String): Boolean {
|
||||
return when (AppInstaller.getCurrentInstaller(appContext)) {
|
||||
Installer.SESSION -> isSAndAbove() && CertUtil.isAuroraStoreApp(appContext, packageName)
|
||||
Installer.NATIVE -> false
|
||||
Installer.ROOT -> AppInstaller.hasRootAccess()
|
||||
Installer.SERVICE -> AppInstaller.hasAuroraService(appContext)
|
||||
Installer.AM -> false // We cannot check if AppManager has ability to auto-update
|
||||
Installer.SHIZUKU -> isOAndAbove() && AppInstaller.hasShizukuOrSui(appContext) &&
|
||||
AppInstaller.hasShizukuPerm()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,6 @@ object CertUtil {
|
||||
private const val CERT_BEGIN = "-----BEGIN CERTIFICATE-----"
|
||||
private const val CERT_END = "-----END CERTIFICATE-----"
|
||||
|
||||
fun isAuroraStoreApp(context: Context, packageName: String): Boolean {
|
||||
return context.packageManager.getInstallerPackageNameCompat(packageName) == context.packageName
|
||||
}
|
||||
|
||||
fun isFDroidApp(context: Context, packageName: String): Boolean {
|
||||
return isInstalledByFDroid(context, packageName) || isSignedByFDroid(context, packageName)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.aurora.Constants
|
||||
import com.aurora.store.MainActivity
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.activity.InstallActivity
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.model.DownloadStatus
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.data.room.update.Update
|
||||
@@ -109,13 +110,17 @@ object NotificationUtil {
|
||||
builder.setAutoCancel(true)
|
||||
builder.setCategory(Notification.CATEGORY_STATUS)
|
||||
builder.setContentIntent(getContentIntentForDetails(context, download.packageName))
|
||||
builder.addAction(
|
||||
NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_install,
|
||||
context.getString(R.string.action_install),
|
||||
getInstallIntent(context, download)
|
||||
).build()
|
||||
)
|
||||
|
||||
// Show install action if app cannot be silently installed
|
||||
if (!AppInstaller.canInstallSilently(context, download.packageName, download.targetSdk)) {
|
||||
builder.addAction(
|
||||
NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_install,
|
||||
context.getString(R.string.action_install),
|
||||
getInstallIntent(context, download)
|
||||
).build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DownloadStatus.DOWNLOADING, DownloadStatus.QUEUED -> {
|
||||
|
||||
Reference in New Issue
Block a user