ktlint: Reformat data directory
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -44,6 +44,6 @@ open class InstallerEvent(open val packageName: String) : Event() {
|
|||||||
data class Failed(
|
data class Failed(
|
||||||
override val packageName: String,
|
override val packageName: String,
|
||||||
val error: String? = null,
|
val error: String? = null,
|
||||||
val extra: String? = null,
|
val extra: String? = null
|
||||||
) : InstallerEvent(packageName)
|
) : InstallerEvent(packageName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package com.aurora.store.data.event
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.aurora.extensions.TAG
|
import com.aurora.extensions.TAG
|
||||||
|
import javax.inject.Singleton
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class EventFlow {
|
class EventFlow {
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ import com.aurora.store.data.room.update.Update
|
|||||||
import com.aurora.store.data.work.DownloadWorker
|
import com.aurora.store.data.work.DownloadWorker
|
||||||
import com.aurora.store.util.PathUtil
|
import com.aurora.store.util.PathUtil
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to work with the [DownloadWorker].
|
* Helper class to work with the [DownloadWorker].
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_IDLE
|
|||||||
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_METERED
|
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_METERED
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import java.util.UUID
|
||||||
|
import java.util.concurrent.TimeUnit.HOURS
|
||||||
|
import java.util.concurrent.TimeUnit.MINUTES
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -32,10 +36,6 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.UUID
|
|
||||||
import java.util.concurrent.TimeUnit.HOURS
|
|
||||||
import java.util.concurrent.TimeUnit.MINUTES
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to work with the [UpdateWorker].
|
* Helper class to work with the [UpdateWorker].
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import com.aurora.extensions.isOAndAbove
|
|||||||
import com.aurora.extensions.isPAndAbove
|
import com.aurora.extensions.isPAndAbove
|
||||||
import com.aurora.extensions.isSAndAbove
|
import com.aurora.extensions.isSAndAbove
|
||||||
import com.aurora.store.BuildConfig
|
import com.aurora.store.BuildConfig
|
||||||
|
import com.aurora.store.data.installer.ShizukuInstaller.Companion.SHIZUKU_PACKAGE_NAME
|
||||||
import com.aurora.store.data.installer.base.IInstaller
|
import com.aurora.store.data.installer.base.IInstaller
|
||||||
import com.aurora.store.data.model.Installer
|
import com.aurora.store.data.model.Installer
|
||||||
import com.aurora.store.data.model.InstallerInfo
|
import com.aurora.store.data.model.InstallerInfo
|
||||||
@@ -40,10 +41,10 @@ import com.aurora.store.util.Preferences
|
|||||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
|
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import rikka.shizuku.Shizuku
|
|
||||||
import rikka.sui.Sui
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import rikka.shizuku.Shizuku
|
||||||
|
import rikka.sui.Sui
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AppInstaller @Inject constructor(
|
class AppInstaller @Inject constructor(
|
||||||
@@ -58,27 +59,28 @@ class AppInstaller @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_INSTALL_STATUS = "com.aurora.store.data.installer.AppInstaller.INSTALL_STATUS"
|
const val ACTION_INSTALL_STATUS =
|
||||||
|
"com.aurora.store.data.installer.AppInstaller.INSTALL_STATUS"
|
||||||
|
|
||||||
const val EXTRA_PACKAGE_NAME = "com.aurora.store.data.installer.AppInstaller.EXTRA_PACKAGE_NAME"
|
const val EXTRA_PACKAGE_NAME =
|
||||||
const val EXTRA_VERSION_CODE = "com.aurora.store.data.installer.AppInstaller.EXTRA_VERSION_CODE"
|
"com.aurora.store.data.installer.AppInstaller.EXTRA_PACKAGE_NAME"
|
||||||
const val EXTRA_DISPLAY_NAME = "com.aurora.store.data.installer.AppInstaller.EXTRA_DISPLAY_NAME"
|
const val EXTRA_VERSION_CODE =
|
||||||
|
"com.aurora.store.data.installer.AppInstaller.EXTRA_VERSION_CODE"
|
||||||
|
const val EXTRA_DISPLAY_NAME =
|
||||||
|
"com.aurora.store.data.installer.AppInstaller.EXTRA_DISPLAY_NAME"
|
||||||
|
|
||||||
fun getCurrentInstaller(context: Context): Installer {
|
fun getCurrentInstaller(context: Context): Installer =
|
||||||
return Installer.entries[Preferences.getInteger(context, PREFERENCE_INSTALLER_ID)]
|
Installer.entries[Preferences.getInteger(context, PREFERENCE_INSTALLER_ID)]
|
||||||
}
|
|
||||||
|
|
||||||
fun getAvailableInstallersInfo(context: Context): List<InstallerInfo> {
|
fun getAvailableInstallersInfo(context: Context): List<InstallerInfo> = listOfNotNull(
|
||||||
return listOfNotNull(
|
SessionInstaller.installerInfo,
|
||||||
SessionInstaller.installerInfo,
|
NativeInstaller.installerInfo,
|
||||||
NativeInstaller.installerInfo,
|
if (hasRootAccess()) RootInstaller.installerInfo else null,
|
||||||
if (hasRootAccess()) RootInstaller.installerInfo else null,
|
if (hasAuroraService(context)) ServiceInstaller.installerInfo else null,
|
||||||
if (hasAuroraService(context)) ServiceInstaller.installerInfo else null,
|
if (hasAppManager(context)) AMInstaller.installerInfo else null,
|
||||||
if (hasAppManager(context)) AMInstaller.installerInfo else null,
|
if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null,
|
||||||
if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null,
|
if (hasMicroGCompanion(context)) MicroGInstaller.installerInfo else null
|
||||||
if (hasMicroGCompanion(context)) MicroGInstaller.installerInfo else null
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given package can be silently installed
|
* Checks if the given package can be silently installed
|
||||||
@@ -92,60 +94,71 @@ class AppInstaller @Inject constructor(
|
|||||||
if (!PackageUtil.isInstalled(context, packageName) || !isSAndAbove) return false
|
if (!PackageUtil.isInstalled(context, packageName) || !isSAndAbove) return false
|
||||||
|
|
||||||
// We cannot do silent updates if we are not the update owner
|
// We cannot do silent updates if we are not the update owner
|
||||||
if (context.packageManager.getUpdateOwnerPackageNameCompat(packageName) != BuildConfig.APPLICATION_ID) return false
|
if (context.packageManager.getUpdateOwnerPackageNameCompat(packageName) !=
|
||||||
|
BuildConfig.APPLICATION_ID
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure app being installed satisfies Android's requirement for targetSdk level
|
// Ensure app being installed satisfies Android's requirement for targetSdk level
|
||||||
when (Build.VERSION.SDK_INT) {
|
when (Build.VERSION.SDK_INT) {
|
||||||
Build.VERSION_CODES.BAKLAVA -> targetSdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|
Build.VERSION_CODES.BAKLAVA -> {
|
||||||
Build.VERSION_CODES.VANILLA_ICE_CREAM -> targetSdk >= Build.VERSION_CODES.TIRAMISU
|
targetSdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|
||||||
|
}
|
||||||
|
|
||||||
|
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.UPSIDE_DOWN_CAKE -> targetSdk >= Build.VERSION_CODES.S
|
||||||
|
|
||||||
Build.VERSION_CODES.TIRAMISU -> targetSdk >= Build.VERSION_CODES.R
|
Build.VERSION_CODES.TIRAMISU -> targetSdk >= Build.VERSION_CODES.R
|
||||||
|
|
||||||
Build.VERSION_CODES.S -> targetSdk >= Build.VERSION_CODES.Q
|
Build.VERSION_CODES.S -> targetSdk >= Build.VERSION_CODES.Q
|
||||||
|
|
||||||
else -> false // Only Android version above 12 can silently update apps
|
else -> false // Only Android version above 12 can silently update apps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Installer.NATIVE -> false // Native installer requires user interaction
|
|
||||||
|
// Native installer requires user interaction
|
||||||
|
Installer.NATIVE -> false
|
||||||
|
|
||||||
Installer.ROOT -> hasRootAccess()
|
Installer.ROOT -> hasRootAccess()
|
||||||
|
|
||||||
Installer.SERVICE -> hasAuroraService(context)
|
Installer.SERVICE -> hasAuroraService(context)
|
||||||
Installer.AM -> false // We cannot check if AppManager has ability to auto-update
|
|
||||||
|
// We cannot check if AppManager has ability to auto-update
|
||||||
|
Installer.AM -> false
|
||||||
|
|
||||||
Installer.SHIZUKU -> isOAndAbove && hasShizukuOrSui(context) && hasShizukuPerm()
|
Installer.SHIZUKU -> isOAndAbove && hasShizukuOrSui(context) && hasShizukuPerm()
|
||||||
|
|
||||||
Installer.MICROG -> false
|
Installer.MICROG -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasRootAccess(): Boolean {
|
fun hasRootAccess(): Boolean = Shell.getShell().isRoot
|
||||||
return Shell.getShell().isRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasAuroraService(context: Context): Boolean {
|
fun hasAuroraService(context: Context): Boolean = try {
|
||||||
return try {
|
val packageInfo = PackageUtil.getPackageInfo(
|
||||||
val packageInfo = PackageUtil.getPackageInfo(
|
|
||||||
context,
|
|
||||||
ServiceInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME
|
|
||||||
)
|
|
||||||
val version = PackageInfoCompat.getLongVersionCode(packageInfo)
|
|
||||||
|
|
||||||
packageInfo.applicationInfo!!.enabled && version >= 9
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasAppManager(context: Context): Boolean {
|
|
||||||
return PackageUtil.isInstalled(context, AMInstaller.AM_PACKAGE_NAME) or
|
|
||||||
PackageUtil.isInstalled(context, AMInstaller.AM_DEBUG_PACKAGE_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasShizukuOrSui(context: Context): Boolean {
|
|
||||||
return isOAndAbove && (PackageUtil.isInstalled(
|
|
||||||
context,
|
context,
|
||||||
ShizukuInstaller.SHIZUKU_PACKAGE_NAME
|
ServiceInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME
|
||||||
) || Sui.isSui())
|
)
|
||||||
|
val version = PackageInfoCompat.getLongVersionCode(packageInfo)
|
||||||
|
|
||||||
|
packageInfo.applicationInfo!!.enabled && version >= 9
|
||||||
|
} catch (_: Exception) {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasShizukuPerm(): Boolean {
|
fun hasAppManager(context: Context): Boolean =
|
||||||
return Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
|
PackageUtil.isInstalled(context, AMInstaller.AM_PACKAGE_NAME) or
|
||||||
}
|
PackageUtil.isInstalled(context, AMInstaller.AM_DEBUG_PACKAGE_NAME)
|
||||||
|
|
||||||
|
fun hasShizukuOrSui(context: Context): Boolean = isOAndAbove &&
|
||||||
|
(PackageUtil.isInstalled(context, SHIZUKU_PACKAGE_NAME) || Sui.isSui())
|
||||||
|
|
||||||
|
fun hasShizukuPerm(): Boolean =
|
||||||
|
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
|
||||||
|
|
||||||
fun uninstall(context: Context, packageName: String) {
|
fun uninstall(context: Context, packageName: String) {
|
||||||
val intent = Intent().apply {
|
val intent = Intent().apply {
|
||||||
@@ -166,25 +179,33 @@ class AppInstaller @Inject constructor(
|
|||||||
private val defaultInstaller: IInstaller
|
private val defaultInstaller: IInstaller
|
||||||
get() = sessionInstaller
|
get() = sessionInstaller
|
||||||
|
|
||||||
fun getMicroGInstaller(): IInstaller {
|
fun getMicroGInstaller(): IInstaller = microGInstaller
|
||||||
return microGInstaller
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPreferredInstaller(): IInstaller {
|
fun getPreferredInstaller(): IInstaller = when (getCurrentInstaller(context)) {
|
||||||
return when (getCurrentInstaller(context)) {
|
Installer.SESSION -> sessionInstaller
|
||||||
Installer.SESSION -> sessionInstaller
|
|
||||||
Installer.NATIVE -> nativeInstaller
|
Installer.NATIVE -> nativeInstaller
|
||||||
Installer.ROOT -> if (hasRootAccess()) rootInstaller else defaultInstaller
|
|
||||||
Installer.SERVICE -> if (hasAuroraService(context)) serviceInstaller else defaultInstaller
|
Installer.ROOT -> if (hasRootAccess()) rootInstaller else defaultInstaller
|
||||||
Installer.AM -> if (hasAppManager(context)) amInstaller else defaultInstaller
|
|
||||||
Installer.SHIZUKU -> {
|
Installer.SERVICE -> if (hasAuroraService(context)) {
|
||||||
if (hasShizukuOrSui(context) && hasShizukuPerm()) {
|
serviceInstaller
|
||||||
shizukuInstaller
|
} else {
|
||||||
} else {
|
defaultInstaller
|
||||||
defaultInstaller
|
}
|
||||||
}
|
|
||||||
}
|
Installer.AM -> if (hasAppManager(context)) amInstaller else defaultInstaller
|
||||||
Installer.MICROG -> if(hasMicroGCompanion(context)) microGInstaller else defaultInstaller
|
|
||||||
|
Installer.SHIZUKU -> if (hasShizukuOrSui(context) && hasShizukuPerm()) {
|
||||||
|
shizukuInstaller
|
||||||
|
} else {
|
||||||
|
defaultInstaller
|
||||||
|
}
|
||||||
|
|
||||||
|
Installer.MICROG -> if (hasMicroGCompanion(context)) {
|
||||||
|
microGInstaller
|
||||||
|
} else {
|
||||||
|
defaultInstaller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,13 +53,12 @@ class MicroGInstaller @Inject constructor(
|
|||||||
description = R.string.microg_installer_desc
|
description = R.string.microg_installer_desc
|
||||||
)
|
)
|
||||||
|
|
||||||
fun buildMicroGInstallIntent(uris: ArrayList<Uri>): Intent {
|
fun buildMicroGInstallIntent(uris: ArrayList<Uri>): Intent =
|
||||||
return Intent("org.microg.vending.action.INSTALL_PACKAGE").apply {
|
Intent("org.microg.vending.action.INSTALL_PACKAGE").apply {
|
||||||
setPackage(PACKAGE_NAME_PLAY_STORE)
|
setPackage(PACKAGE_NAME_PLAY_STORE)
|
||||||
setType("application/vnd.android.package-archive")
|
setType("application/vnd.android.package-archive")
|
||||||
putExtra(Intent.EXTRA_STREAM, uris)
|
putExtra(Intent.EXTRA_STREAM, uris)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun install(download: Download) {
|
override fun install(download: Download) {
|
||||||
|
|||||||
@@ -75,7 +75,10 @@ class RootInstaller @Inject constructor(
|
|||||||
context.getString(R.string.installer_status_failure),
|
context.getString(R.string.installer_status_failure),
|
||||||
context.getString(R.string.installer_root_unavailable)
|
context.getString(R.string.installer_root_unavailable)
|
||||||
)
|
)
|
||||||
Log.e(TAG, " >>>>>>>>>>>>>>>>>>>>>>>>>> NO ROOT ACCESS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
|
Log.e(
|
||||||
|
TAG,
|
||||||
|
" >>>>>>>>>>>>>>>>>>>>>>>>>> NO ROOT ACCESS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,8 +86,9 @@ class RootInstaller @Inject constructor(
|
|||||||
private fun xInstall(packageName: String, versionCode: Long, sharedLibPkgName: String = "") {
|
private fun xInstall(packageName: String, versionCode: Long, sharedLibPkgName: String = "") {
|
||||||
var totalSize = 0
|
var totalSize = 0
|
||||||
|
|
||||||
for (file in getFiles(packageName, versionCode, sharedLibPkgName))
|
for (file in getFiles(packageName, versionCode, sharedLibPkgName)) {
|
||||||
totalSize += file.length().toInt()
|
totalSize += file.length().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
val result: Shell.Result =
|
val result: Shell.Result =
|
||||||
Shell.cmd("pm install-create -i $PLAY_PACKAGE_NAME --user 0 -r -S $totalSize")
|
Shell.cmd("pm install-create -i $PLAY_PACKAGE_NAME --user 0 -r -S $totalSize")
|
||||||
@@ -100,7 +104,9 @@ class RootInstaller @Inject constructor(
|
|||||||
val sessionId = sessionIdMatcher.group(1)?.toInt()
|
val sessionId = sessionIdMatcher.group(1)?.toInt()
|
||||||
if (Shell.getShell().isRoot && sessionId != null) {
|
if (Shell.getShell().isRoot && sessionId != null) {
|
||||||
for (file in getFiles(packageName, versionCode, sharedLibPkgName)) {
|
for (file in getFiles(packageName, versionCode, sharedLibPkgName)) {
|
||||||
Shell.cmd("cat \"${file.absoluteFile}\" | pm install-write -S ${file.length()} $sessionId \"${file.name}\"")
|
Shell.cmd(
|
||||||
|
"cat \"${file.absoluteFile}\" | pm install-write -S ${file.length()} $sessionId \"${file.name}\""
|
||||||
|
)
|
||||||
.exec()
|
.exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +142,5 @@ class RootInstaller @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseError(result: Shell.Result): String {
|
private fun parseError(result: Shell.Result): String = result.err.joinToString(separator = "\n")
|
||||||
return result.err.joinToString(separator = "\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,8 +216,8 @@ class SessionInstaller @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildSessionParams(packageName: String): SessionParams {
|
private fun buildSessionParams(packageName: String): SessionParams =
|
||||||
return SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
|
SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
|
||||||
setAppPackageName(packageName)
|
setAppPackageName(packageName)
|
||||||
setInstallLocation(PackageInfo.INSTALL_LOCATION_AUTO)
|
setInstallLocation(PackageInfo.INSTALL_LOCATION_AUTO)
|
||||||
if (isNAndAbove) {
|
if (isNAndAbove) {
|
||||||
@@ -238,7 +238,6 @@ class SessionInstaller @Inject constructor(
|
|||||||
setApplicationEnabledSettingPersistent()
|
setApplicationEnabledSettingPersistent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun commitInstall(sessionInfo: SessionInfo) {
|
private fun commitInstall(sessionInfo: SessionInfo) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -51,10 +51,10 @@ import com.aurora.store.data.room.download.Download
|
|||||||
import com.aurora.store.util.PackageUtil.isSharedLibraryInstalled
|
import com.aurora.store.util.PackageUtil.isSharedLibraryInstalled
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dev.rikka.tools.refine.Refine
|
import dev.rikka.tools.refine.Refine
|
||||||
import rikka.shizuku.ShizukuBinderWrapper
|
|
||||||
import rikka.shizuku.SystemServiceHelper
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import rikka.shizuku.ShizukuBinderWrapper
|
||||||
|
import rikka.shizuku.SystemServiceHelper
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@@ -99,7 +99,9 @@ class ShizukuInstaller @Inject constructor(
|
|||||||
Refine.unsafeCast<PackageInstaller>(
|
Refine.unsafeCast<PackageInstaller>(
|
||||||
PackageInstallerHidden(iPackageInstaller, PLAY_PACKAGE_NAME, 0)
|
PackageInstallerHidden(iPackageInstaller, PLAY_PACKAGE_NAME, 0)
|
||||||
)
|
)
|
||||||
} else null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun install(download: Download) {
|
override fun install(download: Download) {
|
||||||
|
|||||||
@@ -43,20 +43,40 @@ abstract class InstallerBase(private val context: Context) : IInstaller {
|
|||||||
companion object {
|
companion object {
|
||||||
fun notifyInstallation(context: Context, displayName: String, packageName: String) {
|
fun notifyInstallation(context: Context, displayName: String, packageName: String) {
|
||||||
val notificationManager = context.getSystemService<NotificationManager>()
|
val notificationManager = context.getSystemService<NotificationManager>()
|
||||||
val notification = NotificationUtil.getInstallNotification(context, displayName, packageName)
|
val notification = NotificationUtil.getInstallNotification(
|
||||||
|
context,
|
||||||
|
displayName,
|
||||||
|
packageName
|
||||||
|
)
|
||||||
notificationManager!!.notify(packageName.hashCode(), notification)
|
notificationManager!!.notify(packageName.hashCode(), notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getErrorString(context: Context, status: Int): String {
|
fun getErrorString(context: Context, status: Int): String = when (status) {
|
||||||
return when (status) {
|
PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString(
|
||||||
PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString(R.string.installer_status_user_action)
|
R.string.installer_status_user_action
|
||||||
PackageInstaller.STATUS_FAILURE_BLOCKED -> context.getString(R.string.installer_status_failure_blocked)
|
)
|
||||||
PackageInstaller.STATUS_FAILURE_CONFLICT -> context.getString(R.string.installer_status_failure_conflict)
|
|
||||||
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> context.getString(R.string.installer_status_failure_incompatible)
|
PackageInstaller.STATUS_FAILURE_BLOCKED -> context.getString(
|
||||||
PackageInstaller.STATUS_FAILURE_INVALID -> context.getString(R.string.installer_status_failure_invalid)
|
R.string.installer_status_failure_blocked
|
||||||
PackageInstaller.STATUS_FAILURE_STORAGE -> context.getString(R.string.installer_status_failure_storage)
|
)
|
||||||
else -> context.getString(R.string.installer_status_failure)
|
|
||||||
}
|
PackageInstaller.STATUS_FAILURE_CONFLICT -> context.getString(
|
||||||
|
R.string.installer_status_failure_conflict
|
||||||
|
)
|
||||||
|
|
||||||
|
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> context.getString(
|
||||||
|
R.string.installer_status_failure_incompatible
|
||||||
|
)
|
||||||
|
|
||||||
|
PackageInstaller.STATUS_FAILURE_INVALID -> context.getString(
|
||||||
|
R.string.installer_status_failure_invalid
|
||||||
|
)
|
||||||
|
|
||||||
|
PackageInstaller.STATUS_FAILURE_STORAGE -> context.getString(
|
||||||
|
R.string.installer_status_failure_storage
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> context.getString(R.string.installer_status_failure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,9 +91,8 @@ abstract class InstallerBase(private val context: Context) : IInstaller {
|
|||||||
AuroraApp.enqueuedInstalls.clear()
|
AuroraApp.enqueuedInstalls.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isAlreadyQueued(packageName: String): Boolean {
|
override fun isAlreadyQueued(packageName: String): Boolean =
|
||||||
return AuroraApp.enqueuedInstalls.contains(packageName)
|
AuroraApp.enqueuedInstalls.contains(packageName)
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeFromInstallQueue(packageName: String) {
|
override fun removeFromInstallQueue(packageName: String) {
|
||||||
AuroraApp.enqueuedInstalls.remove(packageName)
|
AuroraApp.enqueuedInstalls.remove(packageName)
|
||||||
@@ -113,11 +132,9 @@ abstract class InstallerBase(private val context: Context) : IInstaller {
|
|||||||
return downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
return downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUri(file: File): Uri {
|
fun getUri(file: File): Uri = FileProvider.getUriForFile(
|
||||||
return FileProvider.getUriForFile(
|
context,
|
||||||
context,
|
"${BuildConfig.APPLICATION_ID}.fileProvider",
|
||||||
"${BuildConfig.APPLICATION_ID}.fileProvider",
|
file
|
||||||
file
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,14 +27,10 @@ data class Black(val packageName: String) {
|
|||||||
var versionName: String = String()
|
var versionName: String = String()
|
||||||
var versionCode: Long = 0
|
var versionCode: Long = 0
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int = packageName.hashCode()
|
||||||
return packageName.hashCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean = when (other) {
|
||||||
return when (other) {
|
is Black -> other.packageName == packageName
|
||||||
is Black -> other.packageName == packageName
|
else -> false
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,14 +55,10 @@ data class ExodusTracker(
|
|||||||
val categories: List<String> = emptyList()
|
val categories: List<String> = emptyList()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int = id
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean = when (other) {
|
||||||
return when (other) {
|
is ExodusTracker -> other.id == id
|
||||||
is ExodusTracker -> other.id == id
|
else -> false
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,10 @@ data class InstallerInfo(
|
|||||||
@StringRes val subtitle: Int,
|
@StringRes val subtitle: Int,
|
||||||
@StringRes val description: Int
|
@StringRes val description: Int
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean = when (other) {
|
||||||
return when (other) {
|
is InstallerInfo -> other.id == id
|
||||||
is InstallerInfo -> other.id == id
|
else -> false
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int = id.hashCode()
|
||||||
return id.hashCode()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,16 +24,12 @@ data class Link(
|
|||||||
var title: String,
|
var title: String,
|
||||||
var subtitle: String,
|
var subtitle: String,
|
||||||
var url: String,
|
var url: String,
|
||||||
var icon: Int,
|
var icon: Int
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean = when (other) {
|
||||||
return when (other) {
|
is Link -> other.id == id
|
||||||
is Link -> other.id == id
|
else -> false
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int = id.hashCode()
|
||||||
return id.hashCode()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,23 +19,18 @@ data class MinimalApp(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun fromApp(app: App): MinimalApp {
|
fun fromApp(app: App): MinimalApp = MinimalApp(
|
||||||
return MinimalApp(
|
app.packageName,
|
||||||
app.packageName,
|
app.versionName,
|
||||||
app.versionName,
|
app.versionCode,
|
||||||
app.versionCode,
|
app.displayName
|
||||||
app.displayName
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fromUpdate(update: Update): MinimalApp {
|
|
||||||
return MinimalApp(
|
|
||||||
update.packageName,
|
|
||||||
update.versionName,
|
|
||||||
update.versionCode,
|
|
||||||
update.displayName
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fun fromUpdate(update: Update): MinimalApp = MinimalApp(
|
||||||
|
update.packageName,
|
||||||
|
update.versionName,
|
||||||
|
update.versionCode,
|
||||||
|
update.displayName
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ import com.aurora.gplayapi.data.models.App
|
|||||||
data class PaginatedAppList(
|
data class PaginatedAppList(
|
||||||
val appList: MutableList<App> = mutableListOf(),
|
val appList: MutableList<App> = mutableListOf(),
|
||||||
var hasMore: Boolean
|
var hasMore: Boolean
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ data class SelfUpdate(
|
|||||||
isFree = true,
|
isFree = true,
|
||||||
isInstalled = true,
|
isInstalled = true,
|
||||||
certificateSetList = CertUtil.getEncodedCertificateHashes(
|
certificateSetList = CertUtil.getEncodedCertificateHashes(
|
||||||
context, context.packageName
|
context,
|
||||||
|
context.packageName
|
||||||
).map {
|
).map {
|
||||||
EncodedCertificateSet(certificateSet = it, sha256 = String())
|
EncodedCertificateSet(certificateSet = it, sha256 = String())
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
|
|||||||
@@ -19,11 +19,8 @@
|
|||||||
|
|
||||||
package com.aurora.store.data.model
|
package com.aurora.store.data.model
|
||||||
|
|
||||||
|
|
||||||
sealed class ViewState {
|
sealed class ViewState {
|
||||||
inline fun <reified T> ViewState.getDataAs(): T {
|
inline fun <reified T> ViewState.getDataAs(): T = (this as? Success<*>)?.data as T
|
||||||
return (this as? Success<*>)?.data as T
|
|
||||||
}
|
|
||||||
|
|
||||||
data object Loading : ViewState()
|
data object Loading : ViewState()
|
||||||
data object Empty : ViewState()
|
data object Empty : ViewState()
|
||||||
@@ -33,7 +30,7 @@ sealed class ViewState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sealed class AuthState {
|
sealed class AuthState {
|
||||||
data object Init: AuthState()
|
data object Init : AuthState()
|
||||||
data object Available : AuthState()
|
data object Available : AuthState()
|
||||||
data object Unavailable : AuthState()
|
data object Unavailable : AuthState()
|
||||||
data object SignedIn : AuthState()
|
data object SignedIn : AuthState()
|
||||||
@@ -68,18 +65,15 @@ sealed class AppState {
|
|||||||
/**
|
/**
|
||||||
* Whether there is some sort of ongoing process related to the app
|
* Whether there is some sort of ongoing process related to the app
|
||||||
*/
|
*/
|
||||||
fun inProgress(): Boolean {
|
fun inProgress(): Boolean =
|
||||||
return this is Downloading || this is Installing || this is Purchasing || this is Queued
|
this is Downloading || this is Installing || this is Purchasing || this is Queued
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Progress of the process related to the app; 0 otherwise
|
* Progress of the process related to the app; 0 otherwise
|
||||||
*/
|
*/
|
||||||
fun progress(): Float {
|
fun progress(): Float = when (this) {
|
||||||
return when (this) {
|
is Downloading -> progress
|
||||||
is Downloading -> progress
|
is Installing -> progress
|
||||||
is Installing -> progress
|
else -> 0F
|
||||||
else -> 0F
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ enum class UpdateMode {
|
|||||||
DISABLED,
|
DISABLED,
|
||||||
CHECK_AND_NOTIFY,
|
CHECK_AND_NOTIFY,
|
||||||
CHECK_AND_INSTALL,
|
CHECK_AND_INSTALL,
|
||||||
CHECK_ONLY,
|
CHECK_ONLY
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ import com.aurora.gplayapi.network.IHttpClient
|
|||||||
import com.aurora.store.BuildConfig.APPLICATION_ID
|
import com.aurora.store.BuildConfig.APPLICATION_ID
|
||||||
import com.aurora.store.BuildConfig.VERSION_CODE
|
import com.aurora.store.BuildConfig.VERSION_CODE
|
||||||
import com.aurora.store.BuildConfig.VERSION_NAME
|
import com.aurora.store.BuildConfig.VERSION_NAME
|
||||||
|
import java.io.IOException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@@ -38,12 +41,9 @@ import okhttp3.Request
|
|||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import java.io.IOException
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IHttpClient {
|
class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient) : IHttpClient {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val POST = "POST"
|
private const val POST = "POST"
|
||||||
@@ -69,7 +69,7 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IH
|
|||||||
fun call(url: String, headers: Map<String, String> = emptyMap()): Response {
|
fun call(url: String, headers: Map<String, String> = emptyMap()): Response {
|
||||||
val request = Request(
|
val request = Request(
|
||||||
url = url.toHttpUrl(),
|
url = url.toHttpUrl(),
|
||||||
headers = headers.toHeaders(),
|
headers = headers.toHeaders()
|
||||||
)
|
)
|
||||||
return okHttpClient.newCall(request).execute()
|
return okHttpClient.newCall(request).execute()
|
||||||
}
|
}
|
||||||
@@ -102,14 +102,12 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IH
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun post(url: String, headers: Map<String, String>, body: ByteArray): PlayResponse {
|
override fun post(url: String, headers: Map<String, String>, body: ByteArray): PlayResponse =
|
||||||
return post(url, headers, body.toRequestBody())
|
post(url, headers, body.toRequestBody())
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun get(url: String, headers: Map<String, String>): PlayResponse {
|
override fun get(url: String, headers: Map<String, String>): PlayResponse =
|
||||||
return get(url, headers, mapOf())
|
get(url, headers, mapOf())
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun get(
|
override fun get(
|
||||||
@@ -136,11 +134,7 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IH
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun get(
|
override fun get(url: String, headers: Map<String, String>, paramString: String): PlayResponse {
|
||||||
url: String,
|
|
||||||
headers: Map<String, String>,
|
|
||||||
paramString: String
|
|
||||||
): PlayResponse {
|
|
||||||
val request = Request(
|
val request = Request(
|
||||||
url = "$url$paramString".toHttpUrl(),
|
url = "$url$paramString".toHttpUrl(),
|
||||||
headers = headers.toHeaders(),
|
headers = headers.toHeaders(),
|
||||||
@@ -165,16 +159,14 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IH
|
|||||||
return urlBuilder.build()
|
return urlBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildPlayResponse(response: Response): PlayResponse {
|
private fun buildPlayResponse(response: Response): PlayResponse = PlayResponse(
|
||||||
return PlayResponse(
|
isSuccessful = response.isSuccessful,
|
||||||
isSuccessful = response.isSuccessful,
|
code = response.code,
|
||||||
code = response.code,
|
responseBytes = response.body.bytes(),
|
||||||
responseBytes = response.body.bytes(),
|
errorString = if (!response.isSuccessful) response.message else String()
|
||||||
errorString = if (!response.isSuccessful) response.message else String()
|
).also {
|
||||||
).also {
|
val isCached = if (response.cacheResponse != null) "CACHED" else "NETWORK"
|
||||||
val isCached = if (response.cacheResponse != null) "CACHED" else "NETWORK"
|
_responseCode.value = response.code
|
||||||
_responseCode.value = response.code
|
Log.i(TAG, "OKHTTP [$isCached] [${response.code}] ${response.request.url}")
|
||||||
Log.i(TAG, "OKHTTP [$isCached] [${response.code}] ${response.request.url}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,5 @@ object IHttpClientModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesIHttpClientInstance(httpClient: HttpClient): IHttpClient {
|
fun providesIHttpClientInstance(httpClient: HttpClient): IHttpClient = httpClient
|
||||||
return httpClient
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,10 +33,6 @@ import dagger.Provides
|
|||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import okhttp3.Cache
|
|
||||||
import okhttp3.CertificatePinner
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@@ -49,6 +45,10 @@ import java.security.cert.CertificateFactory
|
|||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Cache
|
||||||
|
import okhttp3.CertificatePinner
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
@@ -90,13 +90,13 @@ object OkHttpClientModule {
|
|||||||
val googleRootCerts = getGoogleRootCertHashes(context).map { "sha256/$it" }
|
val googleRootCerts = getGoogleRootCertHashes(context).map { "sha256/$it" }
|
||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
|
|
||||||
return CertificatePinner.Builder()
|
return CertificatePinner.Builder()
|
||||||
.add("*.googleapis.com", *googleRootCerts)
|
.add("*.googleapis.com", *googleRootCerts)
|
||||||
.add("*.google.com", *googleRootCerts)
|
.add("*.google.com", *googleRootCerts)
|
||||||
.add("auroraoss.com", "sha256/mEflZT5enoR1FuXLgYYGqnVEoZvmf9c2bVBpiOjYQ0c=") // GTS Root R4
|
.add("auroraoss.com", "sha256/mEflZT5enoR1FuXLgYYGqnVEoZvmf9c2bVBpiOjYQ0c=")
|
||||||
.add("*.exodus-privacy.eu.org", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") // ISRG Root X1
|
.add("*.exodus-privacy.eu.org", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=")
|
||||||
.add("gitlab.com", "sha256/x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=") // USERTrust RSA Certification Authority
|
.add("gitlab.com", "sha256/x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=")
|
||||||
.add("plexus.techlore.tech", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") // ISRG Root X1
|
.add("plexus.techlore.tech", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=")
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +108,11 @@ object OkHttpClientModule {
|
|||||||
val proxyInfo = json.decodeFromString<ProxyInfo>(proxyInfoString)
|
val proxyInfo = json.decodeFromString<ProxyInfo>(proxyInfoString)
|
||||||
|
|
||||||
val proxy = Proxy(
|
val proxy = Proxy(
|
||||||
if (proxyInfo.protocol.removeSuffix("5") == "SOCKS") Proxy.Type.SOCKS else Proxy.Type.HTTP,
|
if (proxyInfo.protocol.removeSuffix("5") == "SOCKS") {
|
||||||
|
Proxy.Type.SOCKS
|
||||||
|
} else {
|
||||||
|
Proxy.Type.HTTP
|
||||||
|
},
|
||||||
InetSocketAddress.createUnresolved(proxyInfo.host, proxyInfo.port)
|
InetSocketAddress.createUnresolved(proxyInfo.host, proxyInfo.port)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -117,9 +121,8 @@ object OkHttpClientModule {
|
|||||||
|
|
||||||
if (!proxyUser.isNullOrBlank() && !proxyPassword.isNullOrBlank()) {
|
if (!proxyUser.isNullOrBlank() && !proxyPassword.isNullOrBlank()) {
|
||||||
Authenticator.setDefault(object : Authenticator() {
|
Authenticator.setDefault(object : Authenticator() {
|
||||||
override fun getPasswordAuthentication(): PasswordAuthentication {
|
override fun getPasswordAuthentication(): PasswordAuthentication =
|
||||||
return PasswordAuthentication(proxyUser, proxyPassword.toCharArray())
|
PasswordAuthentication(proxyUser, proxyPassword.toCharArray())
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return proxy
|
return proxy
|
||||||
@@ -131,25 +134,22 @@ object OkHttpClientModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesCacheDir(@ApplicationContext context: Context): Cache {
|
fun providesCacheDir(@ApplicationContext context: Context): Cache = Cache(
|
||||||
return Cache(
|
directory = File(context.cacheDir, "http_cache"),
|
||||||
directory = File(context.cacheDir, "http_cache"),
|
maxSize = 100L * 1024 * 1024
|
||||||
maxSize = 100L * 1024 * 1024
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getGoogleRootCertHashes(context: Context): List<String> {
|
private fun getGoogleRootCertHashes(context: Context): List<String> = try {
|
||||||
return try {
|
val certs =
|
||||||
val certs = getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca))
|
getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca))
|
||||||
certs.map {
|
certs.map {
|
||||||
val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value)
|
val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value)
|
||||||
messageDigest.update(it.publicKey.encoded)
|
messageDigest.update(it.publicKey.encoded)
|
||||||
Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
|
Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
|
||||||
}
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, "Failed to get SHA256 certificate hash", exception)
|
|
||||||
emptyList()
|
|
||||||
}
|
}
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.e(TAG, "Failed to get SHA256 certificate hash", exception)
|
||||||
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getX509Certificates(inputStream: InputStream): List<X509Certificate> {
|
private fun getX509Certificates(inputStream: InputStream): List<X509Certificate> {
|
||||||
|
|||||||
@@ -78,10 +78,9 @@ class GenericPagingSource<T : Any>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRefreshKey(state: PagingState<Int, T>): Int? {
|
override fun getRefreshKey(state: PagingState<Int, T>): Int? =
|
||||||
return state.anchorPosition?.let { anchorPosition ->
|
state.anchorPosition?.let { anchorPosition ->
|
||||||
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
|
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
|
||||||
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
|
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,8 @@ object AccountProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isLoggedIn(context: Context): Boolean {
|
fun isLoggedIn(context: Context): Boolean =
|
||||||
return Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN, false)
|
Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN, false)
|
||||||
}
|
|
||||||
|
|
||||||
fun getLoginEmail(context: Context): String? {
|
fun getLoginEmail(context: Context): String? {
|
||||||
val email = Preferences.getString(context, Constants.ACCOUNT_EMAIL_PLAIN)
|
val email = Preferences.getString(context, Constants.ACCOUNT_EMAIL_PLAIN)
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ import com.aurora.store.util.Preferences
|
|||||||
import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA
|
import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS
|
import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AuthProvider @Inject constructor(
|
class AuthProvider @Inject constructor(
|
||||||
@@ -70,9 +70,7 @@ class AuthProvider @Inject constructor(
|
|||||||
/**
|
/**
|
||||||
* Checks whether saved AuthData is valid or not
|
* Checks whether saved AuthData is valid or not
|
||||||
*/
|
*/
|
||||||
fun isSavedAuthDataValid(): Boolean {
|
fun isSavedAuthDataValid(): Boolean = AuthHelper.isValid(authData!!)
|
||||||
return AuthHelper.isValid(authData!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds [AuthData] for login using personal Google account
|
* Builds [AuthData] for login using personal Google account
|
||||||
@@ -94,7 +92,7 @@ class AuthProvider @Inject constructor(
|
|||||||
token = token,
|
token = token,
|
||||||
tokenType = tokenType,
|
tokenType = tokenType,
|
||||||
properties = spoofProvider.deviceProperties,
|
properties = spoofProvider.deviceProperties,
|
||||||
locale = spoofProvider.locale,
|
locale = spoofProvider.locale
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
@@ -154,10 +152,15 @@ class AuthProvider @Inject constructor(
|
|||||||
private fun throwError(playResponse: PlayResponse, context: Context) {
|
private fun throwError(playResponse: PlayResponse, context: Context) {
|
||||||
when (playResponse.code) {
|
when (playResponse.code) {
|
||||||
400 -> throw Exception(context.getString(R.string.bad_request))
|
400 -> throw Exception(context.getString(R.string.bad_request))
|
||||||
|
|
||||||
403 -> throw Exception(context.getString(R.string.access_denied_using_vpn))
|
403 -> throw Exception(context.getString(R.string.access_denied_using_vpn))
|
||||||
|
|
||||||
404 -> throw Exception(context.getString(R.string.server_unreachable))
|
404 -> throw Exception(context.getString(R.string.server_unreachable))
|
||||||
|
|
||||||
429 -> throw Exception(context.getString(R.string.login_rate_limited))
|
429 -> throw Exception(context.getString(R.string.login_rate_limited))
|
||||||
|
|
||||||
503 -> throw Exception(context.getString(R.string.server_maintenance))
|
503 -> throw Exception(context.getString(R.string.server_maintenance))
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
if (playResponse.errorString.isNotBlank()) {
|
if (playResponse.errorString.isNotBlank()) {
|
||||||
throw Exception(playResponse.errorString)
|
throw Exception(playResponse.errorString)
|
||||||
|
|||||||
@@ -24,15 +24,15 @@ import android.content.SharedPreferences
|
|||||||
import com.aurora.extensions.isNAndAbove
|
import com.aurora.extensions.isNAndAbove
|
||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Preferences
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class BlacklistProvider @Inject constructor(
|
class BlacklistProvider @Inject constructor(
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
@ApplicationContext val context: Context,
|
@ApplicationContext val context: Context
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -67,19 +67,17 @@ class BlacklistProvider @Inject constructor(
|
|||||||
} else {
|
} else {
|
||||||
Preferences.getString(context, PREFERENCE_BLACKLIST)
|
Preferences.getString(context, PREFERENCE_BLACKLIST)
|
||||||
}
|
}
|
||||||
if (rawBlacklist!!.isEmpty())
|
if (rawBlacklist!!.isEmpty()) {
|
||||||
mutableSetOf()
|
mutableSetOf()
|
||||||
else
|
} else {
|
||||||
json.decodeFromString<MutableSet<String>>(rawBlacklist)
|
json.decodeFromString<MutableSet<String>>(rawBlacklist)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
mutableSetOf()
|
mutableSetOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBlacklisted(packageName: String): Boolean {
|
fun isBlacklisted(packageName: String): Boolean = blacklist.contains(packageName)
|
||||||
return blacklist.contains(packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun blacklist(packageName: String) {
|
fun blacklist(packageName: String) {
|
||||||
blacklist = blacklist.apply {
|
blacklist = blacklist.apply {
|
||||||
|
|||||||
@@ -41,8 +41,10 @@ object EglExtensionProvider {
|
|||||||
val configs = arrayOfNulls<EGLConfig>(configCount[0])
|
val configs = arrayOfNulls<EGLConfig>(configCount[0])
|
||||||
if (egl.eglGetConfigs(display, configs, configCount[0], configCount)) {
|
if (egl.eglGetConfigs(display, configs, configCount[0], configCount)) {
|
||||||
val pbufferAttribs = intArrayOf(
|
val pbufferAttribs = intArrayOf(
|
||||||
EGL10.EGL_WIDTH, EGL10.EGL_PBUFFER_BIT,
|
EGL10.EGL_WIDTH,
|
||||||
EGL10.EGL_HEIGHT, EGL10.EGL_PBUFFER_BIT,
|
EGL10.EGL_PBUFFER_BIT,
|
||||||
|
EGL10.EGL_HEIGHT,
|
||||||
|
EGL10.EGL_PBUFFER_BIT,
|
||||||
EGL10.EGL_NONE
|
EGL10.EGL_NONE
|
||||||
)
|
)
|
||||||
val contextAttributes = intArrayOf(12440, EGL10.EGL_PIXMAP_BIT, EGL10.EGL_NONE)
|
val contextAttributes = intArrayOf(12440, EGL10.EGL_PIXMAP_BIT, EGL10.EGL_NONE)
|
||||||
|
|||||||
@@ -30,15 +30,16 @@ object NativeDeviceInfoProvider {
|
|||||||
|
|
||||||
fun getNativeDeviceProperties(context: Context, isExport: Boolean = false): Properties {
|
fun getNativeDeviceProperties(context: Context, isExport: Boolean = false): Properties {
|
||||||
val properties = Properties().apply {
|
val properties = Properties().apply {
|
||||||
//Build Props
|
// Build Props
|
||||||
setProperty("UserReadableName", "${Build.MANUFACTURER} ${Build.MODEL}")
|
setProperty("UserReadableName", "${Build.MANUFACTURER} ${Build.MODEL}")
|
||||||
setProperty("Build.HARDWARE", Build.HARDWARE)
|
setProperty("Build.HARDWARE", Build.HARDWARE)
|
||||||
setProperty(
|
setProperty(
|
||||||
"Build.RADIO",
|
"Build.RADIO",
|
||||||
if (Build.getRadioVersion() != null)
|
if (Build.getRadioVersion() != null) {
|
||||||
Build.getRadioVersion()
|
Build.getRadioVersion()
|
||||||
else
|
} else {
|
||||||
"unknown"
|
"unknown"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
setProperty("Build.FINGERPRINT", Build.FINGERPRINT)
|
setProperty("Build.FINGERPRINT", Build.FINGERPRINT)
|
||||||
setProperty("Build.BRAND", Build.BRAND)
|
setProperty("Build.BRAND", Build.BRAND)
|
||||||
@@ -62,21 +63,24 @@ object NativeDeviceInfoProvider {
|
|||||||
"${config.navigation == Configuration.NAVIGATIONHIDDEN_YES}"
|
"${config.navigation == Configuration.NAVIGATIONHIDDEN_YES}"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Display Metrics
|
// Display Metrics
|
||||||
val metrics = context.resources.displayMetrics
|
val metrics = context.resources.displayMetrics
|
||||||
setProperty("Screen.Density", "${metrics.densityDpi}")
|
setProperty("Screen.Density", "${metrics.densityDpi}")
|
||||||
setProperty("Screen.Width", "${metrics.widthPixels}")
|
setProperty("Screen.Width", "${metrics.widthPixels}")
|
||||||
setProperty("Screen.Height", "${metrics.heightPixels}")
|
setProperty("Screen.Height", "${metrics.heightPixels}")
|
||||||
|
|
||||||
//Supported Platforms
|
// Supported Platforms
|
||||||
setProperty("Platforms", Build.SUPPORTED_ABIS.joinToString(separator = ","))
|
setProperty("Platforms", Build.SUPPORTED_ABIS.joinToString(separator = ","))
|
||||||
//Supported Features
|
// Supported Features
|
||||||
setProperty("Features", getFeatures(context).joinToString(separator = ","))
|
setProperty("Features", getFeatures(context).joinToString(separator = ","))
|
||||||
//Shared Locales
|
// Shared Locales
|
||||||
setProperty("Locales", getLocales(context).joinToString(separator = ","))
|
setProperty("Locales", getLocales(context).joinToString(separator = ","))
|
||||||
//Shared Libraries
|
// Shared Libraries
|
||||||
setProperty("SharedLibraries", getSharedLibraries(context).joinToString(separator = ","))
|
setProperty(
|
||||||
//GL Extensions
|
"SharedLibraries",
|
||||||
|
getSharedLibraries(context).joinToString(separator = ",")
|
||||||
|
)
|
||||||
|
// GL Extensions
|
||||||
val activityManager = context.getSystemService<ActivityManager>()
|
val activityManager = context.getSystemService<ActivityManager>()
|
||||||
setProperty(
|
setProperty(
|
||||||
"GL.Version",
|
"GL.Version",
|
||||||
@@ -87,7 +91,7 @@ object NativeDeviceInfoProvider {
|
|||||||
EglExtensionProvider.eglExtensions.joinToString(separator = ",")
|
EglExtensionProvider.eglExtensions.joinToString(separator = ",")
|
||||||
)
|
)
|
||||||
|
|
||||||
//Google Related Props
|
// Google Related Props
|
||||||
setProperty("Client", "android-google")
|
setProperty("Client", "android-google")
|
||||||
|
|
||||||
val gsfVersionProvider = NativeGsfVersionProvider(context, isExport)
|
val gsfVersionProvider = NativeGsfVersionProvider(context, isExport)
|
||||||
@@ -95,11 +99,11 @@ object NativeDeviceInfoProvider {
|
|||||||
setProperty("Vending.version", gsfVersionProvider.vendingVersionCode.toString())
|
setProperty("Vending.version", gsfVersionProvider.vendingVersionCode.toString())
|
||||||
setProperty("Vending.versionString", gsfVersionProvider.vendingVersionString)
|
setProperty("Vending.versionString", gsfVersionProvider.vendingVersionString)
|
||||||
|
|
||||||
//MISC
|
// MISC
|
||||||
setProperty("Roaming", "mobile-notroaming")
|
setProperty("Roaming", "mobile-notroaming")
|
||||||
setProperty("TimeZone", "UTC-10")
|
setProperty("TimeZone", "UTC-10")
|
||||||
|
|
||||||
//Telephony (USA 3650 AT&T)
|
// Telephony (USA 3650 AT&T)
|
||||||
setProperty("CellOperator", "310")
|
setProperty("CellOperator", "310")
|
||||||
setProperty("SimOperator", "38")
|
setProperty("SimOperator", "38")
|
||||||
}
|
}
|
||||||
@@ -108,29 +112,23 @@ object NativeDeviceInfoProvider {
|
|||||||
return properties
|
return properties
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFeatures(context: Context): List<String> {
|
private fun getFeatures(context: Context): List<String> = context
|
||||||
return context
|
.packageManager
|
||||||
.packageManager
|
.systemAvailableFeatures
|
||||||
.systemAvailableFeatures
|
.mapNotNull { it.name }
|
||||||
.mapNotNull { it.name }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLocales(context: Context): List<String> {
|
private fun getLocales(context: Context): List<String> = context
|
||||||
return context
|
.assets
|
||||||
.assets
|
.locales
|
||||||
.locales
|
.mapNotNull { it.replace("-", "_") }
|
||||||
.mapNotNull { it.replace("-", "_") }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSharedLibraries(context: Context): List<String> {
|
private fun getSharedLibraries(context: Context): List<String> = context
|
||||||
return context
|
.packageManager
|
||||||
.packageManager
|
.systemSharedLibraryNames
|
||||||
.systemSharedLibraryNames
|
?.toList() ?: emptyList()
|
||||||
?.toList() ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun stripHuaweiProperties(properties: Properties): Properties {
|
private fun stripHuaweiProperties(properties: Properties): Properties {
|
||||||
//Add Pixel 7a properties
|
// Add Pixel 7a properties
|
||||||
properties["Build.HARDWARE"] = "lynx"
|
properties["Build.HARDWARE"] = "lynx"
|
||||||
properties["Build.BOOTLOADER"] = "lynx-1.0-9716681"
|
properties["Build.BOOTLOADER"] = "lynx-1.0-9716681"
|
||||||
properties["Build.BRAND"] = "google"
|
properties["Build.BRAND"] = "google"
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ import androidx.core.content.getSystemService
|
|||||||
import com.aurora.extensions.isNAndAbove
|
import com.aurora.extensions.isNAndAbove
|
||||||
import com.aurora.store.data.model.NetworkStatus
|
import com.aurora.store.data.model.NetworkStatus
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple provider with a flow to observe internet connectivity changes
|
* A simple provider with a flow to observe internet connectivity changes
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ class PermissionProvider(private val fragment: Fragment) :
|
|||||||
/**
|
/**
|
||||||
* Checks whether a known permission has been granted
|
* Checks whether a known permission has been granted
|
||||||
*/
|
*/
|
||||||
fun isGranted(context: Context, permissionType: PermissionType): Boolean {
|
fun isGranted(context: Context, permissionType: PermissionType): Boolean =
|
||||||
return when (permissionType) {
|
when (permissionType) {
|
||||||
PermissionType.EXTERNAL_STORAGE,
|
PermissionType.EXTERNAL_STORAGE,
|
||||||
PermissionType.STORAGE_MANAGER -> {
|
PermissionType.STORAGE_MANAGER -> {
|
||||||
context.isExternalStorageAccessible()
|
context.isExternalStorageAccessible()
|
||||||
@@ -76,9 +76,8 @@ class PermissionProvider(private val fragment: Fragment) :
|
|||||||
PermissionType.DOZE_WHITELIST -> context.isIgnoringBatteryOptimizations()
|
PermissionType.DOZE_WHITELIST -> context.isIgnoringBatteryOptimizations()
|
||||||
|
|
||||||
PermissionType.APP_LINKS -> context.isDomainVerified("play.google.com") &&
|
PermissionType.APP_LINKS -> context.isDomainVerified("play.google.com") &&
|
||||||
context.isDomainVerified("market.android.com")
|
context.isDomainVerified("market.android.com")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all known permissions that can be requested by Aurora Store
|
* Returns all known permissions that can be requested by Aurora Store
|
||||||
@@ -132,7 +131,9 @@ class PermissionProvider(private val fragment: Fragment) :
|
|||||||
Permission(
|
Permission(
|
||||||
type = PermissionType.POST_NOTIFICATIONS,
|
type = PermissionType.POST_NOTIFICATIONS,
|
||||||
title = context.getString(R.string.onboarding_permission_notifications),
|
title = context.getString(R.string.onboarding_permission_notifications),
|
||||||
subtitle = context.getString(R.string.onboarding_permission_notifications_desc),
|
subtitle = context.getString(
|
||||||
|
R.string.onboarding_permission_notifications_desc
|
||||||
|
),
|
||||||
optional = true,
|
optional = true,
|
||||||
isGranted = isGranted(context, PermissionType.POST_NOTIFICATIONS)
|
isGranted = isGranted(context, PermissionType.POST_NOTIFICATIONS)
|
||||||
)
|
)
|
||||||
@@ -147,7 +148,7 @@ class PermissionProvider(private val fragment: Fragment) :
|
|||||||
subtitle = context.getString(R.string.app_links_desc),
|
subtitle = context.getString(R.string.app_links_desc),
|
||||||
optional = true,
|
optional = true,
|
||||||
isGranted = isGranted(context, PermissionType.APP_LINKS)
|
isGranted = isGranted(context, PermissionType.APP_LINKS)
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +196,7 @@ class PermissionProvider(private val fragment: Fragment) :
|
|||||||
if (!isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS)) {
|
if (!isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS)) {
|
||||||
context.toast(R.string.toast_permission_installer_required)
|
context.toast(R.string.toast_permission_installer_required)
|
||||||
} else {
|
} else {
|
||||||
/**
|
/*
|
||||||
* I don't know why, but for storage manager permission on Android 11 & 12,
|
* I don't know why, but for storage manager permission on Android 11 & 12,
|
||||||
* we need to request both permissions otherwise the permission is not granted,
|
* we need to request both permissions otherwise the permission is not granted,
|
||||||
* even though OS says it is granted.
|
* even though OS says it is granted.
|
||||||
@@ -231,18 +232,16 @@ class PermissionProvider(private val fragment: Fragment) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
private fun knownPermissions(): Map<PermissionType, Intent> {
|
private fun knownPermissions(): Map<PermissionType, Intent> = mapOf(
|
||||||
return mapOf(
|
PermissionType.STORAGE_MANAGER to PackageUtil.getStorageManagerIntent(context),
|
||||||
PermissionType.STORAGE_MANAGER to PackageUtil.getStorageManagerIntent(context),
|
PermissionType.INSTALL_UNKNOWN_APPS to PackageUtil.getInstallUnknownAppsIntent(),
|
||||||
PermissionType.INSTALL_UNKNOWN_APPS to PackageUtil.getInstallUnknownAppsIntent(),
|
PermissionType.DOZE_WHITELIST to Intent(
|
||||||
PermissionType.DOZE_WHITELIST to Intent(
|
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||||
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
"package:${BuildConfig.APPLICATION_ID}".toUri()
|
||||||
"package:${BuildConfig.APPLICATION_ID}".toUri()
|
),
|
||||||
),
|
PermissionType.APP_LINKS to Intent(
|
||||||
PermissionType.APP_LINKS to Intent(
|
ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
|
||||||
ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
|
"package:${BuildConfig.APPLICATION_ID}".toUri()
|
||||||
"package:${BuildConfig.APPLICATION_ID}".toUri()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,12 +137,9 @@ open class SpoofDeviceProvider(private val context: Context) {
|
|||||||
return File(sourceDir)
|
return File(sourceDir)
|
||||||
}
|
}
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
|
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filenameValid(filename: String): Boolean {
|
private fun filenameValid(filename: String): Boolean = filename.endsWith(SUFFIX)
|
||||||
return filename.endsWith(SUFFIX)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ import com.aurora.store.R
|
|||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Preferences
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION
|
import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provider class to work with device and locale spoofs
|
* Provider class to work with device and locale spoofs
|
||||||
@@ -36,7 +36,7 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
class SpoofProvider @Inject constructor(
|
class SpoofProvider @Inject constructor(
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
@ApplicationContext val context: Context,
|
@ApplicationContext val context: Context
|
||||||
) : SpoofDeviceProvider(context) {
|
) : SpoofDeviceProvider(context) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -119,7 +119,10 @@ class SpoofProvider @Inject constructor(
|
|||||||
val versionStrings = resources.getStringArray(R.array.pref_vending_version)
|
val versionStrings = resources.getStringArray(R.array.pref_vending_version)
|
||||||
|
|
||||||
currentProperties.setProperty("Vending.version", versionCodes[vendingVersionIndex])
|
currentProperties.setProperty("Vending.version", versionCodes[vendingVersionIndex])
|
||||||
currentProperties.setProperty("Vending.versionString", versionStrings[vendingVersionIndex])
|
currentProperties.setProperty(
|
||||||
|
"Vending.versionString",
|
||||||
|
versionStrings[vendingVersionIndex]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import com.aurora.extensions.TAG
|
|||||||
import com.aurora.store.AuroraApp
|
import com.aurora.store.AuroraApp
|
||||||
import com.aurora.store.data.helper.DownloadHelper
|
import com.aurora.store.data.helper.DownloadHelper
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class DownloadCancelReceiver : BroadcastReceiver() {
|
class DownloadCancelReceiver : BroadcastReceiver() {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class MigrationReceiver : BroadcastReceiver() {
|
|||||||
if (CertUtil.isAppGalleryApp(context, context.packageName)) {
|
if (CertUtil.isAppGalleryApp(context, context.packageName)) {
|
||||||
val dispensers = Preferences.getStringSet(context, PREFERENCE_DISPENSER_URLS)
|
val dispensers = Preferences.getStringSet(context, PREFERENCE_DISPENSER_URLS)
|
||||||
.toMutableSet()
|
.toMutableSet()
|
||||||
|
|
||||||
dispensers.remove(Constants.URL_DISPENSER)
|
dispensers.remove(Constants.URL_DISPENSER)
|
||||||
|
|
||||||
context.save(PREFERENCE_DISPENSER_URLS, dispensers)
|
context.save(PREFERENCE_DISPENSER_URLS, dispensers)
|
||||||
@@ -75,7 +75,8 @@ class MigrationReceiver : BroadcastReceiver() {
|
|||||||
// 63 -> 64
|
// 63 -> 64
|
||||||
if (currentVersion == 2) {
|
if (currentVersion == 2) {
|
||||||
if (isOAndAbove) {
|
if (isOAndAbove) {
|
||||||
with(context.getSystemService<NotificationManager>()!!) { // !1189
|
with(context.getSystemService<NotificationManager>()!!) {
|
||||||
|
// !1189
|
||||||
deleteNotificationChannel("NOTIFICATION_CHANNEL_GENERAL")
|
deleteNotificationChannel("NOTIFICATION_CHANNEL_GENERAL")
|
||||||
deleteNotificationChannel("NOTIFICATION_CHANNEL_ALERT")
|
deleteNotificationChannel("NOTIFICATION_CHANNEL_ALERT")
|
||||||
}
|
}
|
||||||
@@ -87,10 +88,11 @@ class MigrationReceiver : BroadcastReceiver() {
|
|||||||
if (currentVersion == 3) {
|
if (currentVersion == 3) {
|
||||||
val updateMode = UpdateMode.entries[
|
val updateMode = UpdateMode.entries[
|
||||||
Preferences.getInteger(
|
Preferences.getInteger(
|
||||||
context,
|
context,
|
||||||
PREFERENCE_UPDATES_AUTO,
|
PREFERENCE_UPDATES_AUTO,
|
||||||
UpdateMode.DISABLED.ordinal
|
UpdateMode.DISABLED.ordinal
|
||||||
)]
|
)
|
||||||
|
]
|
||||||
|
|
||||||
if (updateMode != UpdateMode.DISABLED) {
|
if (updateMode != UpdateMode.DISABLED) {
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ open class PackageManagerReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clear installation queue
|
// Clear installation queue
|
||||||
appInstaller.getPreferredInstaller().removeFromInstallQueue(packageName)
|
appInstaller.getPreferredInstaller().removeFromInstallQueue(packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ import com.aurora.store.data.helper.DownloadHelper
|
|||||||
import com.aurora.store.data.providers.AccountProvider
|
import com.aurora.store.data.providers.AccountProvider
|
||||||
import com.aurora.store.util.NotificationUtil
|
import com.aurora.store.util.NotificationUtil
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers re-install/unarchive of a previously archived app on Android 15+ devices.
|
* Triggers re-install/unarchive of a previously archived app on Android 15+ devices.
|
||||||
*/
|
*/
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class UnarchivePackageReceiver: BroadcastReceiver() {
|
class UnarchivePackageReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var appDetailsHelper: AppDetailsHelper
|
lateinit var appDetailsHelper: AppDetailsHelper
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ object MigrationHelper {
|
|||||||
private fun migrateFrom1To2(database: SupportSQLiteDatabase) {
|
private fun migrateFrom1To2(database: SupportSQLiteDatabase) {
|
||||||
database.beginTransaction()
|
database.beginTransaction()
|
||||||
try {
|
try {
|
||||||
database.execSQL("CREATE TABLE `favourite` (`packageName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `added` INTEGER NOT NULL, `mode` TEXT NOT NULL, PRIMARY KEY(`packageName`))")
|
database.execSQL(
|
||||||
|
"CREATE TABLE `favourite` (`packageName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `added` INTEGER NOT NULL, `mode` TEXT NOT NULL, PRIMARY KEY(`packageName`))"
|
||||||
|
)
|
||||||
database.setTransactionSuccessful()
|
database.setTransactionSuccessful()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed while migrating from database version 1 to 2", exception)
|
Log.e(TAG, "Failed while migrating from database version 1 to 2", exception)
|
||||||
@@ -47,7 +49,9 @@ object MigrationHelper {
|
|||||||
private fun migrateFrom2To3(database: SupportSQLiteDatabase) {
|
private fun migrateFrom2To3(database: SupportSQLiteDatabase) {
|
||||||
database.beginTransaction()
|
database.beginTransaction()
|
||||||
try {
|
try {
|
||||||
database.execSQL("CREATE TABLE `update` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `versionName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `changelog` TEXT NOT NULL, `id` INTEGER NOT NULL, `developerName` TEXT NOT NULL, `size` INTEGER NOT NULL, `updatedOn` TEXT NOT NULL, `hasValidCert` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, PRIMARY KEY(`packageName`))")
|
database.execSQL(
|
||||||
|
"CREATE TABLE `update` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `versionName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `changelog` TEXT NOT NULL, `id` INTEGER NOT NULL, `developerName` TEXT NOT NULL, `size` INTEGER NOT NULL, `updatedOn` TEXT NOT NULL, `hasValidCert` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, PRIMARY KEY(`packageName`))"
|
||||||
|
)
|
||||||
database.setTransactionSuccessful()
|
database.setTransactionSuccessful()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed while migrating from database version 2 to 3", exception)
|
Log.e(TAG, "Failed while migrating from database version 2 to 3", exception)
|
||||||
@@ -63,7 +67,9 @@ object MigrationHelper {
|
|||||||
database.beginTransaction()
|
database.beginTransaction()
|
||||||
try {
|
try {
|
||||||
listOf("download", "update").forEach {
|
listOf("download", "update").forEach {
|
||||||
database.execSQL("ALTER TABLE `$it` ADD COLUMN targetSdk INTEGER NOT NULL DEFAULT 1")
|
database.execSQL(
|
||||||
|
"ALTER TABLE `$it` ADD COLUMN targetSdk INTEGER NOT NULL DEFAULT 1"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
database.setTransactionSuccessful()
|
database.setTransactionSuccessful()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
@@ -79,7 +85,9 @@ object MigrationHelper {
|
|||||||
private fun migrateFrom4To5(database: SupportSQLiteDatabase) {
|
private fun migrateFrom4To5(database: SupportSQLiteDatabase) {
|
||||||
database.beginTransaction()
|
database.beginTransaction()
|
||||||
try {
|
try {
|
||||||
database.execSQL("ALTER TABLE `download` ADD COLUMN downloadedAt INTEGER NOT NULL DEFAULT 0")
|
database.execSQL(
|
||||||
|
"ALTER TABLE `download` ADD COLUMN downloadedAt INTEGER NOT NULL DEFAULT 0"
|
||||||
|
)
|
||||||
database.setTransactionSuccessful()
|
database.setTransactionSuccessful()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed while migrating from database version 4 to 5", exception)
|
Log.e(TAG, "Failed while migrating from database version 4 to 5", exception)
|
||||||
|
|||||||
@@ -29,25 +29,25 @@ object RoomModule {
|
|||||||
fun providesRoomInstance(
|
fun providesRoomInstance(
|
||||||
@ApplicationContext context: Context,
|
@ApplicationContext context: Context,
|
||||||
downloadConverter: DownloadConverter
|
downloadConverter: DownloadConverter
|
||||||
): AuroraDatabase {
|
): AuroraDatabase = Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE)
|
||||||
return Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE)
|
.addMigrations(
|
||||||
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
|
MIGRATION_1_2,
|
||||||
.addTypeConverter(downloadConverter)
|
MIGRATION_2_3,
|
||||||
.build()
|
MIGRATION_3_4,
|
||||||
}
|
MIGRATION_4_5,
|
||||||
|
MIGRATION_5_6
|
||||||
|
)
|
||||||
|
.addTypeConverter(downloadConverter)
|
||||||
|
.build()
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao {
|
fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao =
|
||||||
return auroraDatabase.downloadDao()
|
auroraDatabase.downloadDao()
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesFavouriteDao(auroraDatabase: AuroraDatabase): FavouriteDao {
|
fun providesFavouriteDao(auroraDatabase: AuroraDatabase): FavouriteDao =
|
||||||
return auroraDatabase.favouriteDao()
|
auroraDatabase.favouriteDao()
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesUpdateDao(auroraDatabase: AuroraDatabase): UpdateDao {
|
fun providesUpdateDao(auroraDatabase: AuroraDatabase): UpdateDao = auroraDatabase.updateDao()
|
||||||
return auroraDatabase.updateDao()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import com.aurora.store.data.model.DownloadStatus
|
|||||||
import com.aurora.store.data.room.suite.ExternalApk
|
import com.aurora.store.data.room.suite.ExternalApk
|
||||||
import com.aurora.store.data.room.update.Update
|
import com.aurora.store.data.room.update.Update
|
||||||
import com.aurora.store.util.PathUtil
|
import com.aurora.store.util.PathUtil
|
||||||
import kotlinx.parcelize.Parcelize
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Entity(tableName = "download")
|
@Entity(tableName = "download")
|
||||||
@@ -44,73 +44,67 @@ data class Download(
|
|||||||
private val isSuccessful get() = status == DownloadStatus.COMPLETED
|
private val isSuccessful get() = status == DownloadStatus.COMPLETED
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromApp(app: App): Download {
|
fun fromApp(app: App): Download = Download(
|
||||||
return Download(
|
app.packageName,
|
||||||
app.packageName,
|
app.versionCode,
|
||||||
app.versionCode,
|
app.offerType,
|
||||||
app.offerType,
|
app.isInstalled,
|
||||||
app.isInstalled,
|
app.displayName,
|
||||||
app.displayName,
|
app.iconArtwork.url,
|
||||||
app.iconArtwork.url,
|
app.size,
|
||||||
app.size,
|
app.id,
|
||||||
app.id,
|
DownloadStatus.QUEUED,
|
||||||
DownloadStatus.QUEUED,
|
0,
|
||||||
0,
|
0L,
|
||||||
0L,
|
0L,
|
||||||
0L,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
app.fileList.filterNot { it.url.isBlank() },
|
||||||
app.fileList.filterNot { it.url.isBlank() },
|
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
|
||||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
|
app.targetSdk,
|
||||||
app.targetSdk,
|
Date().time,
|
||||||
Date().time,
|
app.requiresGMS()
|
||||||
app.requiresGMS()
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fromUpdate(update: Update): Download {
|
fun fromUpdate(update: Update): Download = Download(
|
||||||
return Download(
|
update.packageName,
|
||||||
update.packageName,
|
update.versionCode,
|
||||||
update.versionCode,
|
update.offerType,
|
||||||
update.offerType,
|
true,
|
||||||
true,
|
update.displayName,
|
||||||
update.displayName,
|
update.iconURL,
|
||||||
update.iconURL,
|
update.size,
|
||||||
update.size,
|
update.id,
|
||||||
update.id,
|
DownloadStatus.QUEUED,
|
||||||
DownloadStatus.QUEUED,
|
0,
|
||||||
0,
|
0L,
|
||||||
0L,
|
0L,
|
||||||
0L,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
update.fileList,
|
||||||
update.fileList,
|
update.sharedLibs,
|
||||||
update.sharedLibs,
|
update.targetSdk,
|
||||||
update.targetSdk,
|
Date().time
|
||||||
Date().time
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fromExternalApk(externalApk: ExternalApk): Download {
|
fun fromExternalApk(externalApk: ExternalApk): Download = Download(
|
||||||
return Download(
|
packageName = externalApk.packageName,
|
||||||
packageName = externalApk.packageName,
|
versionCode = externalApk.versionCode,
|
||||||
versionCode = externalApk.versionCode,
|
offerType = 0,
|
||||||
offerType = 0,
|
isInstalled = false,
|
||||||
isInstalled = false,
|
displayName = externalApk.displayName,
|
||||||
displayName = externalApk.displayName,
|
iconURL = externalApk.iconURL,
|
||||||
iconURL = externalApk.iconURL,
|
size = 0,
|
||||||
size = 0,
|
id = 0,
|
||||||
id = 0,
|
status = DownloadStatus.QUEUED,
|
||||||
status = DownloadStatus.QUEUED,
|
progress = 0,
|
||||||
progress = 0,
|
speed = 0L,
|
||||||
speed = 0L,
|
timeRemaining = 0L,
|
||||||
timeRemaining = 0L,
|
totalFiles = 1,
|
||||||
totalFiles = 1,
|
downloadedFiles = 0,
|
||||||
downloadedFiles = 0,
|
fileList = externalApk.fileList,
|
||||||
fileList = externalApk.fileList,
|
sharedLibs = emptyList()
|
||||||
sharedLibs = emptyList(),
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun canInstall(context: Context): Boolean {
|
fun canInstall(context: Context): Boolean {
|
||||||
|
|||||||
@@ -3,31 +3,25 @@ package com.aurora.store.data.room.download
|
|||||||
import androidx.room.ProvidedTypeConverter
|
import androidx.room.ProvidedTypeConverter
|
||||||
import androidx.room.TypeConverter
|
import androidx.room.TypeConverter
|
||||||
import com.aurora.gplayapi.data.models.PlayFile
|
import com.aurora.gplayapi.data.models.PlayFile
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ProvidedTypeConverter
|
@ProvidedTypeConverter
|
||||||
class DownloadConverter @Inject constructor(private val json: Json) {
|
class DownloadConverter @Inject constructor(private val json: Json) {
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun toSharedLibList(string: String): List<SharedLib> {
|
fun toSharedLibList(string: String): List<SharedLib> =
|
||||||
return json.decodeFromString<List<SharedLib>>(string)
|
json.decodeFromString<List<SharedLib>>(string)
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun fromSharedLibList(list: List<SharedLib>): String {
|
fun fromSharedLibList(list: List<SharedLib>): String = json.encodeToString(list)
|
||||||
return json.encodeToString(list)
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun toGPlayFileList(string: String): List<PlayFile> {
|
fun toGPlayFileList(string: String): List<PlayFile> =
|
||||||
return json.decodeFromString<List<PlayFile>>(string)
|
json.decodeFromString<List<PlayFile>>(string)
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun fromGPlayFileList(list: List<PlayFile>): String {
|
fun fromGPlayFileList(list: List<PlayFile>): String = json.encodeToString(list)
|
||||||
return json.encodeToString(list)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,7 @@ interface DownloadDao {
|
|||||||
WHERE packageName=:packageName
|
WHERE packageName=:packageName
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
suspend fun updateProgress(
|
suspend fun updateProgress(packageName: String, progress: Int, speed: Long, timeRemaining: Long)
|
||||||
packageName: String,
|
|
||||||
progress: Int,
|
|
||||||
speed: Long,
|
|
||||||
timeRemaining: Long
|
|
||||||
)
|
|
||||||
|
|
||||||
@Query("SELECT * FROM download")
|
@Query("SELECT * FROM download")
|
||||||
fun downloads(): Flow<List<Download>>
|
fun downloads(): Flow<List<Download>>
|
||||||
|
|||||||
@@ -14,12 +14,10 @@ data class SharedLib(
|
|||||||
var fileList: List<PlayFile>
|
var fileList: List<PlayFile>
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromApp(app: App): SharedLib {
|
fun fromApp(app: App): SharedLib = SharedLib(
|
||||||
return SharedLib(
|
app.packageName,
|
||||||
app.packageName,
|
app.versionCode,
|
||||||
app.versionCode,
|
app.fileList.filterNot { it.url.isBlank() }
|
||||||
app.fileList.filterNot { it.url.isBlank() }
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,23 +21,19 @@ data class Favourite(
|
|||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromApp(app: App, mode: Mode): Favourite {
|
fun fromApp(app: App, mode: Mode): Favourite = Favourite(
|
||||||
return Favourite(
|
packageName = app.packageName,
|
||||||
packageName = app.packageName,
|
displayName = app.displayName,
|
||||||
displayName = app.displayName,
|
iconURL = app.iconArtwork.url,
|
||||||
iconURL = app.iconArtwork.url,
|
added = System.currentTimeMillis(),
|
||||||
added = System.currentTimeMillis(),
|
mode = mode
|
||||||
mode = mode
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Favourite.toApp(): App {
|
fun Favourite.toApp(): App = App(
|
||||||
return App(
|
packageName = packageName,
|
||||||
packageName = packageName,
|
displayName = displayName,
|
||||||
displayName = displayName,
|
iconArtwork = Artwork(url = iconURL)
|
||||||
iconArtwork = Artwork(url = iconURL)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ import kotlinx.serialization.Serializable
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class ImportExport(
|
data class ImportExport(
|
||||||
val favourites: List<Favourite>,
|
val favourites: List<Favourite>,
|
||||||
val auroraStoreVersion: Int = BuildConfig.VERSION_CODE,
|
val auroraStoreVersion: Int = BuildConfig.VERSION_CODE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,7 +21,5 @@ data class ExternalApk(
|
|||||||
var fileList: List<PlayFile>
|
var fileList: List<PlayFile>
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
fun isInstalled(context: Context): Boolean {
|
fun isInstalled(context: Context): Boolean = PackageUtil.isInstalled(context, packageName)
|
||||||
return PackageUtil.isInstalled(context, packageName)
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,40 +33,34 @@ data class Update(
|
|||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromApp(context: Context, app: App): Update {
|
fun fromApp(context: Context, app: App): Update = Update(
|
||||||
return Update(
|
app.packageName,
|
||||||
app.packageName,
|
app.versionCode,
|
||||||
app.versionCode,
|
app.versionName,
|
||||||
app.versionName,
|
app.displayName,
|
||||||
app.displayName,
|
app.iconArtwork.url,
|
||||||
app.iconArtwork.url,
|
app.changes,
|
||||||
app.changes,
|
app.id,
|
||||||
app.id,
|
app.developerName,
|
||||||
app.developerName,
|
app.size,
|
||||||
app.size,
|
app.updatedOn,
|
||||||
app.updatedOn,
|
app.certificateSetList.any {
|
||||||
app.certificateSetList.any {
|
it.certificateSet in CertUtil.getEncodedCertificateHashes(
|
||||||
it.certificateSet in CertUtil.getEncodedCertificateHashes(
|
context,
|
||||||
context, app.packageName
|
app.packageName
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
app.offerType,
|
app.offerType,
|
||||||
app.fileList.filterNot { it.url.isBlank() },
|
app.fileList.filterNot { it.url.isBlank() },
|
||||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
|
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
|
||||||
app.targetSdk
|
app.targetSdk
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isSelfUpdate(context: Context): Boolean {
|
fun isSelfUpdate(context: Context): Boolean = packageName == context.packageName
|
||||||
return packageName == context.packageName
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isInstalled(context: Context): Boolean {
|
fun isInstalled(context: Context): Boolean = PackageUtil.isInstalled(context, packageName)
|
||||||
return PackageUtil.isInstalled(context, packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isUpToDate(context: Context): Boolean {
|
fun isUpToDate(context: Context): Boolean =
|
||||||
return PackageUtil.isInstalled(context, packageName, versionCode)
|
PackageUtil.isInstalled(context, packageName, versionCode)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ open class AuthWorker @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchAuthToken(email: String, oldToken: String? = null): String {
|
private suspend fun fetchAuthToken(email: String, oldToken: String? = null): String =
|
||||||
return suspendCoroutine { continuation ->
|
suspendCoroutine { continuation ->
|
||||||
fetchAuthToken(email, oldToken) { future ->
|
fetchAuthToken(email, oldToken) { future ->
|
||||||
try {
|
try {
|
||||||
val bundle = future.result
|
val bundle = future.result
|
||||||
@@ -110,14 +110,15 @@ open class AuthWorker @AssistedInject constructor(
|
|||||||
if (token != null) {
|
if (token != null) {
|
||||||
continuation.resume(token)
|
continuation.resume(token)
|
||||||
} else {
|
} else {
|
||||||
continuation.resumeWithException(IllegalStateException("Auth token is null"))
|
continuation.resumeWithException(
|
||||||
|
IllegalStateException("Auth token is null")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
continuation.resumeWithException(e)
|
continuation.resumeWithException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchAuthToken(
|
private fun fetchAuthToken(
|
||||||
email: String,
|
email: String,
|
||||||
@@ -155,8 +156,8 @@ open class AuthWorker @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType): AuthData? {
|
private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType): AuthData? =
|
||||||
return if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) {
|
if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) {
|
||||||
authProvider.saveAuthData(authData)
|
authProvider.saveAuthData(authData)
|
||||||
AccountProvider.login(
|
AccountProvider.login(
|
||||||
context,
|
context,
|
||||||
@@ -171,5 +172,4 @@ open class AuthWorker @AssistedInject constructor(
|
|||||||
AccountProvider.logout(context)
|
AccountProvider.logout(context)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,19 +58,23 @@ class CacheWorker @AssistedInject constructor(
|
|||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
Log.i(TAG, "Cleaning cache")
|
Log.i(TAG, "Cleaning cache")
|
||||||
|
|
||||||
PathUtil.getOldDownloadDirectories(context).filter { it.exists() }.forEach { dir -> // Downloads
|
PathUtil.getOldDownloadDirectories(context).filter { it.exists() }.forEach { dir ->
|
||||||
|
// Downloads
|
||||||
Log.i(TAG, "Deleting old unused download directory: $dir")
|
Log.i(TAG, "Deleting old unused download directory: $dir")
|
||||||
dir.deleteRecursively()
|
dir.deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
PathUtil.getDownloadDirectory(context).listFiles()?.forEach { download -> // com.example.app
|
PathUtil.getDownloadDirectory(context).listFiles()?.forEach { download ->
|
||||||
|
// com.example.app
|
||||||
// Delete if the download directory is empty
|
// Delete if the download directory is empty
|
||||||
if (download.listFiles().isNullOrEmpty()) {
|
if (download.listFiles().isNullOrEmpty()) {
|
||||||
Log.i(TAG, "Removing empty download directory for ${download.name}")
|
Log.i(TAG, "Removing empty download directory for ${download.name}")
|
||||||
download.deleteRecursively(); return@forEach
|
download.deleteRecursively()
|
||||||
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
download.listFiles()!!.forEach { versionCode -> // 20240325
|
download.listFiles()!!.forEach { versionCode ->
|
||||||
|
// 20240325
|
||||||
if (versionCode.listFiles().isNullOrEmpty()) {
|
if (versionCode.listFiles().isNullOrEmpty()) {
|
||||||
// Purge empty non-accessible directory
|
// Purge empty non-accessible directory
|
||||||
Log.i(TAG, "Removing empty directory for ${download.name}, ${versionCode.name}")
|
Log.i(TAG, "Removing empty directory for ${download.name}, ${versionCode.name}")
|
||||||
|
|||||||
@@ -48,9 +48,6 @@ import com.aurora.store.util.PackageUtil
|
|||||||
import com.aurora.store.util.PathUtil
|
import com.aurora.store.util.PathUtil
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.NonCancellable
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
@@ -60,6 +57,9 @@ import java.security.DigestInputStream
|
|||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import kotlin.coroutines.cancellation.CancellationException
|
import kotlin.coroutines.cancellation.CancellationException
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.NonCancellable
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expedited long-running worker to download and trigger installation for given apps.
|
* An expedited long-running worker to download and trigger installation for given apps.
|
||||||
@@ -206,10 +206,13 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
private suspend fun onSuccess(): Result {
|
private suspend fun onSuccess(): Result {
|
||||||
return withContext(NonCancellable) {
|
return withContext(NonCancellable) {
|
||||||
return@withContext try {
|
return@withContext try {
|
||||||
if (BuildConfig.FLAVOR == FLAVOUR_HUAWEI && download.requiresGMS && PackageUtil.hasMicroGCompanion(context))
|
if (BuildConfig.FLAVOR == FLAVOUR_HUAWEI && download.requiresGMS &&
|
||||||
|
PackageUtil.hasMicroGCompanion(context)
|
||||||
|
) {
|
||||||
appInstaller.getMicroGInstaller().install(download)
|
appInstaller.getMicroGInstaller().install(download)
|
||||||
else
|
} else {
|
||||||
appInstaller.getPreferredInstaller().install(download)
|
appInstaller.getPreferredInstaller().install(download)
|
||||||
|
}
|
||||||
Result.success()
|
Result.success()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed to install ${download.packageName}", exception)
|
Log.e(TAG, "Failed to install ${download.packageName}", exception)
|
||||||
@@ -425,7 +428,10 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val notification = NotificationUtil.getDownloadNotification(
|
val notification = NotificationUtil.getDownloadNotification(
|
||||||
context, download, icon, exception?.message
|
context,
|
||||||
|
download,
|
||||||
|
icon,
|
||||||
|
exception?.message
|
||||||
)
|
)
|
||||||
notificationManager.notify(
|
notificationManager.notify(
|
||||||
if (isProgress) NOTIFICATION_ID else download.packageName.hashCode(),
|
if (isProgress) NOTIFICATION_ID else download.packageName.hashCode(),
|
||||||
@@ -453,7 +459,10 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
file.inputStream().use { fis ->
|
file.inputStream().use { fis ->
|
||||||
DigestInputStream(fis, messageDigest).use { dis ->
|
DigestInputStream(fis, messageDigest).use { dis ->
|
||||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||||
while (dis.read(buffer) != -1) { /* Just read, digest updates automatically */
|
while (dis.read(buffer) !=
|
||||||
|
-1
|
||||||
|
) {
|
||||||
|
/* Just read, digest updates automatically */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ class ExportWorker @AssistedInject constructor(
|
|||||||
|
|
||||||
notificationManager = context.getSystemService<NotificationManager>()!!
|
notificationManager = context.getSystemService<NotificationManager>()!!
|
||||||
|
|
||||||
|
@Suppress("ktlint:standard:mixed-condition-operators")
|
||||||
if (packageName.isNullOrEmpty() || isDownload && versionCode == -1L) {
|
if (packageName.isNullOrEmpty() || isDownload && versionCode == -1L) {
|
||||||
Log.e(TAG, "Input data is corrupt, bailing out!")
|
Log.e(TAG, "Input data is corrupt, bailing out!")
|
||||||
notifyStatus(displayName ?: String(), uri, false)
|
notifyStatus(displayName ?: String(), uri, false)
|
||||||
@@ -126,12 +127,10 @@ class ExportWorker @AssistedInject constructor(
|
|||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
override suspend fun getForegroundInfo(): ForegroundInfo = ForegroundInfo(
|
||||||
return ForegroundInfo(
|
NOTIFICATION_ID_FGS,
|
||||||
NOTIFICATION_ID_FGS,
|
NotificationUtil.getExportNotification(context)
|
||||||
NotificationUtil.getExportNotification(context)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun notifyStatus(packageName: String, uri: Uri, success: Boolean = true) {
|
private fun notifyStatus(packageName: String, uri: Uri, success: Boolean = true) {
|
||||||
notificationManager.notify(
|
notificationManager.notify(
|
||||||
@@ -157,12 +156,10 @@ class ExportWorker @AssistedInject constructor(
|
|||||||
bundleAllAPKs(fileList.filterNotNull(), uri)
|
bundleAllAPKs(fileList.filterNotNull(), uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyDownloadedApp(packageName: String, versionCode: Long, uri: Uri) {
|
private fun copyDownloadedApp(packageName: String, versionCode: Long, uri: Uri) = bundleAllAPKs(
|
||||||
return bundleAllAPKs(
|
PathUtil.getAppDownloadDir(context, packageName, versionCode).listFiles()!!.toList(),
|
||||||
PathUtil.getAppDownloadDir(context, packageName, versionCode).listFiles()!!.toList(),
|
uri
|
||||||
uri
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bundles all the given APKs to a zip file
|
* Bundles all the given APKs to a zip file
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ import com.aurora.store.util.Preferences
|
|||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
import java.util.Locale
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A worker to check for updates for installed apps based on saved authentication data,
|
* A worker to check for updates for installed apps based on saved authentication data,
|
||||||
@@ -61,8 +61,8 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
private val notificationID = 100
|
private val notificationID = 100
|
||||||
|
|
||||||
private val canSelfUpdate = !CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID) &&
|
private val canSelfUpdate = !CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID) &&
|
||||||
!CertUtil.isAppGalleryApp(context, BuildConfig.APPLICATION_ID) &&
|
!CertUtil.isAppGalleryApp(context, BuildConfig.APPLICATION_ID) &&
|
||||||
BuildType.CURRENT != BuildType.DEBUG
|
BuildType.CURRENT != BuildType.DEBUG
|
||||||
|
|
||||||
private val isAuroraOnlyFilterEnabled: Boolean
|
private val isAuroraOnlyFilterEnabled: Boolean
|
||||||
get() = Preferences.getBoolean(context, Preferences.PREFERENCE_FILTER_AURORA_ONLY, false)
|
get() = Preferences.getBoolean(context, Preferences.PREFERENCE_FILTER_AURORA_ONLY, false)
|
||||||
@@ -77,14 +77,16 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
super.doWork()
|
super.doWork()
|
||||||
|
|
||||||
Log.i(TAG, "Checking for app updates")
|
Log.i(TAG, "Checking for app updates")
|
||||||
val updateMode = UpdateMode.entries[inputData.getInt(
|
val updateMode = UpdateMode.entries[
|
||||||
UpdateHelper.UPDATE_MODE,
|
inputData.getInt(
|
||||||
Preferences.getInteger(
|
UpdateHelper.UPDATE_MODE,
|
||||||
context,
|
Preferences.getInteger(
|
||||||
PREFERENCE_UPDATES_AUTO,
|
context,
|
||||||
UpdateMode.CHECK_AND_INSTALL.ordinal
|
PREFERENCE_UPDATES_AUTO,
|
||||||
|
UpdateMode.CHECK_AND_INSTALL.ordinal
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)]
|
]
|
||||||
|
|
||||||
if (updateMode == UpdateMode.DISABLED || !AccountProvider.isLoggedIn(context)) {
|
if (updateMode == UpdateMode.DISABLED || !AccountProvider.isLoggedIn(context)) {
|
||||||
Log.i(TAG, "Updates are disabled, bailing out!")
|
Log.i(TAG, "Updates are disabled, bailing out!")
|
||||||
@@ -107,7 +109,9 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify and exit if we are only checking for updates or if battery optimizations are enabled
|
// Notify and exit if we are only checking for updates or if battery optimizations are enabled
|
||||||
if (updateMode == UpdateMode.CHECK_AND_NOTIFY || !context.isIgnoringBatteryOptimizations()) {
|
if (updateMode == UpdateMode.CHECK_AND_NOTIFY ||
|
||||||
|
!context.isIgnoringBatteryOptimizations()
|
||||||
|
) {
|
||||||
Log.i(TAG, "Found ${updates.size} updates, notifying!")
|
Log.i(TAG, "Found ${updates.size} updates, notifying!")
|
||||||
notifyUpdates(updates)
|
notifyUpdates(updates)
|
||||||
return Result.success()
|
return Result.success()
|
||||||
@@ -123,7 +127,10 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
|
|
||||||
// Notify about apps that cannot be auto-updated
|
// Notify about apps that cannot be auto-updated
|
||||||
if (filteredUpdates.second.isNotEmpty()) {
|
if (filteredUpdates.second.isNotEmpty()) {
|
||||||
Log.i(TAG, "Found ${updates.size} updates out of which ${filteredUpdates.second.size} cannot be auto-updated")
|
Log.i(
|
||||||
|
TAG,
|
||||||
|
"Found ${updates.size} updates out of which ${filteredUpdates.second.size} cannot be auto-updated"
|
||||||
|
)
|
||||||
notifyUpdates(filteredUpdates.second)
|
notifyUpdates(filteredUpdates.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,12 +144,10 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
override suspend fun getForegroundInfo(): ForegroundInfo = ForegroundInfo(
|
||||||
return ForegroundInfo(
|
notificationID,
|
||||||
notificationID,
|
NotificationUtil.getUpdateNotification(context)
|
||||||
NotificationUtil.getUpdateNotification(context)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks and returns updates for all possible apps
|
* Checks and returns updates for all possible apps
|
||||||
@@ -157,12 +162,18 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
val filteredPackages = if (isAuroraOnlyFilterEnabled) {
|
val filteredPackages = if (isAuroraOnlyFilterEnabled) {
|
||||||
packages.filter { CertUtil.isAuroraStoreApp(context, it.packageName) }
|
packages.filter { CertUtil.isAuroraStoreApp(context, it.packageName) }
|
||||||
} else {
|
} else {
|
||||||
packages.filterNot { if (isFDroidFilterEnabled) CertUtil.isFDroidApp(context, it.packageName) else false }
|
packages.filterNot {
|
||||||
}
|
if (isFDroidFilterEnabled) {
|
||||||
|
CertUtil.isFDroidApp(context, it.packageName)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.map { it.packageName }
|
||||||
|
|
||||||
val updates = appDetailsHelper.getAppByPackageName(filteredPackages.map { it.packageName })
|
val updates = appDetailsHelper.getAppByPackageName(filteredPackages)
|
||||||
.filter { it.displayName.isNotEmpty() }
|
.filter { it.displayName.isNotEmpty() }
|
||||||
.filter { PackageUtil.isUpdatable(context, it.packageName, it.versionCode.toLong()) }
|
.filter { PackageUtil.isUpdatable(context, it.packageName, it.versionCode) }
|
||||||
.toMutableList()
|
.toMutableList()
|
||||||
|
|
||||||
if (canSelfUpdate) getSelfUpdate()?.let { updates.add(it) }
|
if (canSelfUpdate) getSelfUpdate()?.let { updates.add(it) }
|
||||||
@@ -179,7 +190,9 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val updateUrl = when (BuildType.CURRENT) {
|
val updateUrl = when (BuildType.CURRENT) {
|
||||||
BuildType.RELEASE -> Constants.UPDATE_URL_STABLE
|
BuildType.RELEASE -> Constants.UPDATE_URL_STABLE
|
||||||
|
|
||||||
BuildType.NIGHTLY -> Constants.UPDATE_URL_NIGHTLY
|
BuildType.NIGHTLY -> Constants.UPDATE_URL_NIGHTLY
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Log.i(TAG, "Self-updates are not available for this build!")
|
Log.i(TAG, "Self-updates are not available for this build!")
|
||||||
return@withContext null
|
return@withContext null
|
||||||
@@ -193,6 +206,7 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
val isUpdate = when (BuildType.CURRENT) {
|
val isUpdate = when (BuildType.CURRENT) {
|
||||||
BuildType.NIGHTLY,
|
BuildType.NIGHTLY,
|
||||||
BuildType.RELEASE -> selfUpdate.versionCode > BuildConfig.VERSION_CODE
|
BuildType.RELEASE -> selfUpdate.versionCode > BuildConfig.VERSION_CODE
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user