ktlint: Reformat data directory

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2026-01-01 11:41:09 +08:00
parent be13f86a37
commit 5452385c6d
51 changed files with 558 additions and 551 deletions

View File

@@ -44,6 +44,6 @@ open class InstallerEvent(open val packageName: String) : Event() {
data class Failed(
override val packageName: String,
val error: String? = null,
val extra: String? = null,
val extra: String? = null
) : InstallerEvent(packageName)
}

View File

@@ -2,9 +2,9 @@ package com.aurora.store.data.event
import android.util.Log
import com.aurora.extensions.TAG
import javax.inject.Singleton
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import javax.inject.Singleton
@Singleton
class EventFlow {

View File

@@ -18,13 +18,13 @@ import com.aurora.store.data.room.update.Update
import com.aurora.store.data.work.DownloadWorker
import com.aurora.store.util.PathUtil
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
* Helper class to work with the [DownloadWorker].

View File

@@ -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.PREFERENCE_UPDATES_CHECK_INTERVAL
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.firstOrNull
import kotlinx.coroutines.flow.launchIn
@@ -32,10 +36,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
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].

View File

@@ -31,6 +31,7 @@ import com.aurora.extensions.isOAndAbove
import com.aurora.extensions.isPAndAbove
import com.aurora.extensions.isSAndAbove
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.model.Installer
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.topjohnwu.superuser.Shell
import dagger.hilt.android.qualifiers.ApplicationContext
import rikka.shizuku.Shizuku
import rikka.sui.Sui
import javax.inject.Inject
import javax.inject.Singleton
import rikka.shizuku.Shizuku
import rikka.sui.Sui
@Singleton
class AppInstaller @Inject constructor(
@@ -58,27 +59,28 @@ class AppInstaller @Inject constructor(
) {
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_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"
const val EXTRA_PACKAGE_NAME =
"com.aurora.store.data.installer.AppInstaller.EXTRA_PACKAGE_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 {
return Installer.entries[Preferences.getInteger(context, PREFERENCE_INSTALLER_ID)]
}
fun getCurrentInstaller(context: Context): Installer =
Installer.entries[Preferences.getInteger(context, PREFERENCE_INSTALLER_ID)]
fun getAvailableInstallersInfo(context: Context): List<InstallerInfo> {
return listOfNotNull(
SessionInstaller.installerInfo,
NativeInstaller.installerInfo,
if (hasRootAccess()) RootInstaller.installerInfo else null,
if (hasAuroraService(context)) ServiceInstaller.installerInfo else null,
if (hasAppManager(context)) AMInstaller.installerInfo else null,
if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null,
if (hasMicroGCompanion(context)) MicroGInstaller.installerInfo else null
)
}
fun getAvailableInstallersInfo(context: Context): List<InstallerInfo> = listOfNotNull(
SessionInstaller.installerInfo,
NativeInstaller.installerInfo,
if (hasRootAccess()) RootInstaller.installerInfo else null,
if (hasAuroraService(context)) ServiceInstaller.installerInfo else null,
if (hasAppManager(context)) AMInstaller.installerInfo else null,
if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null,
if (hasMicroGCompanion(context)) MicroGInstaller.installerInfo else null
)
/**
* 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
// 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
when (Build.VERSION.SDK_INT) {
Build.VERSION_CODES.BAKLAVA -> targetSdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
Build.VERSION_CODES.VANILLA_ICE_CREAM -> targetSdk >= Build.VERSION_CODES.TIRAMISU
Build.VERSION_CODES.BAKLAVA -> {
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.TIRAMISU -> targetSdk >= Build.VERSION_CODES.R
Build.VERSION_CODES.S -> targetSdk >= Build.VERSION_CODES.Q
else -> false // Only Android version above 12 can silently update apps
}
}
Installer.NATIVE -> false // Native installer requires user interaction
// Native installer requires user interaction
Installer.NATIVE -> false
Installer.ROOT -> hasRootAccess()
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.MICROG -> false
}
}
fun hasRootAccess(): Boolean {
return Shell.getShell().isRoot
}
fun hasRootAccess(): Boolean = Shell.getShell().isRoot
fun hasAuroraService(context: Context): Boolean {
return try {
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(
fun hasAuroraService(context: Context): Boolean = try {
val packageInfo = PackageUtil.getPackageInfo(
context,
ShizukuInstaller.SHIZUKU_PACKAGE_NAME
) || Sui.isSui())
ServiceInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME
)
val version = PackageInfoCompat.getLongVersionCode(packageInfo)
packageInfo.applicationInfo!!.enabled && version >= 9
} catch (_: Exception) {
false
}
fun hasShizukuPerm(): Boolean {
return Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
}
fun hasAppManager(context: Context): Boolean =
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) {
val intent = Intent().apply {
@@ -166,25 +179,33 @@ class AppInstaller @Inject constructor(
private val defaultInstaller: IInstaller
get() = sessionInstaller
fun getMicroGInstaller(): IInstaller {
return microGInstaller
}
fun getMicroGInstaller(): IInstaller = microGInstaller
fun getPreferredInstaller(): IInstaller {
return when (getCurrentInstaller(context)) {
Installer.SESSION -> sessionInstaller
Installer.NATIVE -> nativeInstaller
Installer.ROOT -> if (hasRootAccess()) rootInstaller else defaultInstaller
Installer.SERVICE -> if (hasAuroraService(context)) serviceInstaller else defaultInstaller
Installer.AM -> if (hasAppManager(context)) amInstaller else defaultInstaller
Installer.SHIZUKU -> {
if (hasShizukuOrSui(context) && hasShizukuPerm()) {
shizukuInstaller
} else {
defaultInstaller
}
}
Installer.MICROG -> if(hasMicroGCompanion(context)) microGInstaller else defaultInstaller
fun getPreferredInstaller(): IInstaller = when (getCurrentInstaller(context)) {
Installer.SESSION -> sessionInstaller
Installer.NATIVE -> nativeInstaller
Installer.ROOT -> if (hasRootAccess()) rootInstaller else defaultInstaller
Installer.SERVICE -> if (hasAuroraService(context)) {
serviceInstaller
} else {
defaultInstaller
}
Installer.AM -> if (hasAppManager(context)) amInstaller else defaultInstaller
Installer.SHIZUKU -> if (hasShizukuOrSui(context) && hasShizukuPerm()) {
shizukuInstaller
} else {
defaultInstaller
}
Installer.MICROG -> if (hasMicroGCompanion(context)) {
microGInstaller
} else {
defaultInstaller
}
}
}

View File

@@ -53,13 +53,12 @@ class MicroGInstaller @Inject constructor(
description = R.string.microg_installer_desc
)
fun buildMicroGInstallIntent(uris: ArrayList<Uri>): Intent {
return Intent("org.microg.vending.action.INSTALL_PACKAGE").apply {
fun buildMicroGInstallIntent(uris: ArrayList<Uri>): Intent =
Intent("org.microg.vending.action.INSTALL_PACKAGE").apply {
setPackage(PACKAGE_NAME_PLAY_STORE)
setType("application/vnd.android.package-archive")
putExtra(Intent.EXTRA_STREAM, uris)
}
}
}
override fun install(download: Download) {

View File

@@ -75,7 +75,10 @@ class RootInstaller @Inject constructor(
context.getString(R.string.installer_status_failure),
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 = "") {
var totalSize = 0
for (file in getFiles(packageName, versionCode, sharedLibPkgName))
for (file in getFiles(packageName, versionCode, sharedLibPkgName)) {
totalSize += file.length().toInt()
}
val result: Shell.Result =
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()
if (Shell.getShell().isRoot && sessionId != null) {
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()
}
@@ -136,7 +142,5 @@ class RootInstaller @Inject constructor(
}
}
private fun parseError(result: Shell.Result): String {
return result.err.joinToString(separator = "\n")
}
private fun parseError(result: Shell.Result): String = result.err.joinToString(separator = "\n")
}

View File

@@ -216,8 +216,8 @@ class SessionInstaller @Inject constructor(
}
}
private fun buildSessionParams(packageName: String): SessionParams {
return SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
private fun buildSessionParams(packageName: String): SessionParams =
SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
setAppPackageName(packageName)
setInstallLocation(PackageInfo.INSTALL_LOCATION_AUTO)
if (isNAndAbove) {
@@ -238,7 +238,6 @@ class SessionInstaller @Inject constructor(
setApplicationEnabledSettingPersistent()
}
}
}
private fun commitInstall(sessionInfo: SessionInfo) {
try {

View File

@@ -51,10 +51,10 @@ import com.aurora.store.data.room.download.Download
import com.aurora.store.util.PackageUtil.isSharedLibraryInstalled
import dagger.hilt.android.qualifiers.ApplicationContext
import dev.rikka.tools.refine.Refine
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper
import javax.inject.Inject
import javax.inject.Singleton
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper
@Singleton
@RequiresApi(Build.VERSION_CODES.O)
@@ -99,7 +99,9 @@ class ShizukuInstaller @Inject constructor(
Refine.unsafeCast<PackageInstaller>(
PackageInstallerHidden(iPackageInstaller, PLAY_PACKAGE_NAME, 0)
)
} else null
} else {
null
}
}
override fun install(download: Download) {

View File

@@ -43,20 +43,40 @@ abstract class InstallerBase(private val context: Context) : IInstaller {
companion object {
fun notifyInstallation(context: Context, displayName: String, packageName: String) {
val notificationManager = context.getSystemService<NotificationManager>()
val notification = NotificationUtil.getInstallNotification(context, displayName, packageName)
val notification = NotificationUtil.getInstallNotification(
context,
displayName,
packageName
)
notificationManager!!.notify(packageName.hashCode(), notification)
}
fun getErrorString(context: Context, status: Int): String {
return when (status) {
PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString(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_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)
}
fun getErrorString(context: Context, status: Int): String = when (status) {
PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString(
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_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()
}
override fun isAlreadyQueued(packageName: String): Boolean {
return AuroraApp.enqueuedInstalls.contains(packageName)
}
override fun isAlreadyQueued(packageName: String): Boolean =
AuroraApp.enqueuedInstalls.contains(packageName)
override fun removeFromInstallQueue(packageName: String) {
AuroraApp.enqueuedInstalls.remove(packageName)
@@ -113,11 +132,9 @@ abstract class InstallerBase(private val context: Context) : IInstaller {
return downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
}
fun getUri(file: File): Uri {
return FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileProvider",
file
)
}
fun getUri(file: File): Uri = FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileProvider",
file
)
}

View File

@@ -27,14 +27,10 @@ data class Black(val packageName: String) {
var versionName: String = String()
var versionCode: Long = 0
override fun hashCode(): Int {
return packageName.hashCode()
}
override fun hashCode(): Int = packageName.hashCode()
override fun equals(other: Any?): Boolean {
return when (other) {
is Black -> other.packageName == packageName
else -> false
}
override fun equals(other: Any?): Boolean = when (other) {
is Black -> other.packageName == packageName
else -> false
}
}

View File

@@ -55,14 +55,10 @@ data class ExodusTracker(
val categories: List<String> = emptyList()
) {
override fun hashCode(): Int {
return id
}
override fun hashCode(): Int = id
override fun equals(other: Any?): Boolean {
return when (other) {
is ExodusTracker -> other.id == id
else -> false
}
override fun equals(other: Any?): Boolean = when (other) {
is ExodusTracker -> other.id == id
else -> false
}
}

View File

@@ -33,14 +33,10 @@ data class InstallerInfo(
@StringRes val subtitle: Int,
@StringRes val description: Int
) {
override fun equals(other: Any?): Boolean {
return when (other) {
is InstallerInfo -> other.id == id
else -> false
}
override fun equals(other: Any?): Boolean = when (other) {
is InstallerInfo -> other.id == id
else -> false
}
override fun hashCode(): Int {
return id.hashCode()
}
override fun hashCode(): Int = id.hashCode()
}

View File

@@ -24,16 +24,12 @@ data class Link(
var title: String,
var subtitle: String,
var url: String,
var icon: Int,
var icon: Int
) {
override fun equals(other: Any?): Boolean {
return when (other) {
is Link -> other.id == id
else -> false
}
override fun equals(other: Any?): Boolean = when (other) {
is Link -> other.id == id
else -> false
}
override fun hashCode(): Int {
return id.hashCode()
}
override fun hashCode(): Int = id.hashCode()
}

View File

@@ -19,23 +19,18 @@ data class MinimalApp(
companion object {
fun fromApp(app: App): MinimalApp {
return MinimalApp(
app.packageName,
app.versionName,
app.versionCode,
app.displayName
)
}
fun fromUpdate(update: Update): MinimalApp {
return MinimalApp(
update.packageName,
update.versionName,
update.versionCode,
update.displayName
)
}
fun fromApp(app: App): MinimalApp = MinimalApp(
app.packageName,
app.versionName,
app.versionCode,
app.displayName
)
fun fromUpdate(update: Update): MinimalApp = MinimalApp(
update.packageName,
update.versionName,
update.versionCode,
update.displayName
)
}
}

View File

@@ -5,4 +5,4 @@ import com.aurora.gplayapi.data.models.App
data class PaginatedAppList(
val appList: MutableList<App> = mutableListOf(),
var hasMore: Boolean
)
)

View File

@@ -74,7 +74,8 @@ data class SelfUpdate(
isFree = true,
isInstalled = true,
certificateSetList = CertUtil.getEncodedCertificateHashes(
context, context.packageName
context,
context.packageName
).map {
EncodedCertificateSet(certificateSet = it, sha256 = String())
}.toMutableList()

View File

@@ -19,11 +19,8 @@
package com.aurora.store.data.model
sealed class ViewState {
inline fun <reified T> ViewState.getDataAs(): T {
return (this as? Success<*>)?.data as T
}
inline fun <reified T> ViewState.getDataAs(): T = (this as? Success<*>)?.data as T
data object Loading : ViewState()
data object Empty : ViewState()
@@ -33,7 +30,7 @@ sealed class ViewState {
}
sealed class AuthState {
data object Init: AuthState()
data object Init : AuthState()
data object Available : AuthState()
data object Unavailable : AuthState()
data object SignedIn : AuthState()
@@ -68,18 +65,15 @@ sealed class AppState {
/**
* Whether there is some sort of ongoing process related to the app
*/
fun inProgress(): Boolean {
return this is Downloading || this is Installing || this is Purchasing || this is Queued
}
fun inProgress(): Boolean =
this is Downloading || this is Installing || this is Purchasing || this is Queued
/**
* Progress of the process related to the app; 0 otherwise
*/
fun progress(): Float {
return when (this) {
is Downloading -> progress
is Installing -> progress
else -> 0F
}
fun progress(): Float = when (this) {
is Downloading -> progress
is Installing -> progress
else -> 0F
}
}

View File

@@ -4,5 +4,5 @@ enum class UpdateMode {
DISABLED,
CHECK_AND_NOTIFY,
CHECK_AND_INSTALL,
CHECK_ONLY,
CHECK_ONLY
}

View File

@@ -26,6 +26,9 @@ import com.aurora.gplayapi.network.IHttpClient
import com.aurora.store.BuildConfig.APPLICATION_ID
import com.aurora.store.BuildConfig.VERSION_CODE
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.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -38,12 +41,9 @@ import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import java.io.IOException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IHttpClient {
class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient) : IHttpClient {
companion object {
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 {
val request = Request(
url = url.toHttpUrl(),
headers = headers.toHeaders(),
headers = headers.toHeaders()
)
return okHttpClient.newCall(request).execute()
}
@@ -102,14 +102,12 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IH
}
@Throws(IOException::class)
override fun post(url: String, headers: Map<String, String>, body: ByteArray): PlayResponse {
return post(url, headers, body.toRequestBody())
}
override fun post(url: String, headers: Map<String, String>, body: ByteArray): PlayResponse =
post(url, headers, body.toRequestBody())
@Throws(IOException::class)
override fun get(url: String, headers: Map<String, String>): PlayResponse {
return get(url, headers, mapOf())
}
override fun get(url: String, headers: Map<String, String>): PlayResponse =
get(url, headers, mapOf())
@Throws(IOException::class)
override fun get(
@@ -136,11 +134,7 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IH
}
@Throws(IOException::class)
override fun get(
url: String,
headers: Map<String, String>,
paramString: String
): PlayResponse {
override fun get(url: String, headers: Map<String, String>, paramString: String): PlayResponse {
val request = Request(
url = "$url$paramString".toHttpUrl(),
headers = headers.toHeaders(),
@@ -165,16 +159,14 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IH
return urlBuilder.build()
}
private fun buildPlayResponse(response: Response): PlayResponse {
return PlayResponse(
isSuccessful = response.isSuccessful,
code = response.code,
responseBytes = response.body.bytes(),
errorString = if (!response.isSuccessful) response.message else String()
).also {
val isCached = if (response.cacheResponse != null) "CACHED" else "NETWORK"
_responseCode.value = response.code
Log.i(TAG, "OKHTTP [$isCached] [${response.code}] ${response.request.url}")
}
private fun buildPlayResponse(response: Response): PlayResponse = PlayResponse(
isSuccessful = response.isSuccessful,
code = response.code,
responseBytes = response.body.bytes(),
errorString = if (!response.isSuccessful) response.message else String()
).also {
val isCached = if (response.cacheResponse != null) "CACHED" else "NETWORK"
_responseCode.value = response.code
Log.i(TAG, "OKHTTP [$isCached] [${response.code}] ${response.request.url}")
}
}

View File

@@ -13,7 +13,5 @@ object IHttpClientModule {
@Provides
@Singleton
fun providesIHttpClientInstance(httpClient: HttpClient): IHttpClient {
return httpClient
}
fun providesIHttpClientInstance(httpClient: HttpClient): IHttpClient = httpClient
}

View File

@@ -33,10 +33,6 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
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.File
import java.io.InputStream
@@ -49,6 +45,10 @@ import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
import kotlinx.serialization.json.Json
import okhttp3.Cache
import okhttp3.CertificatePinner
import okhttp3.OkHttpClient
@Module
@InstallIn(SingletonComponent::class)
@@ -90,13 +90,13 @@ object OkHttpClientModule {
val googleRootCerts = getGoogleRootCertHashes(context).map { "sha256/$it" }
.toTypedArray()
return CertificatePinner.Builder()
return CertificatePinner.Builder()
.add("*.googleapis.com", *googleRootCerts)
.add("*.google.com", *googleRootCerts)
.add("auroraoss.com", "sha256/mEflZT5enoR1FuXLgYYGqnVEoZvmf9c2bVBpiOjYQ0c=") // GTS Root R4
.add("*.exodus-privacy.eu.org", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") // ISRG Root X1
.add("gitlab.com", "sha256/x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=") // USERTrust RSA Certification Authority
.add("plexus.techlore.tech", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") // ISRG Root X1
.add("auroraoss.com", "sha256/mEflZT5enoR1FuXLgYYGqnVEoZvmf9c2bVBpiOjYQ0c=")
.add("*.exodus-privacy.eu.org", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=")
.add("gitlab.com", "sha256/x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=")
.add("plexus.techlore.tech", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=")
.build()
}
@@ -108,7 +108,11 @@ object OkHttpClientModule {
val proxyInfo = json.decodeFromString<ProxyInfo>(proxyInfoString)
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)
)
@@ -117,9 +121,8 @@ object OkHttpClientModule {
if (!proxyUser.isNullOrBlank() && !proxyPassword.isNullOrBlank()) {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(proxyUser, proxyPassword.toCharArray())
}
override fun getPasswordAuthentication(): PasswordAuthentication =
PasswordAuthentication(proxyUser, proxyPassword.toCharArray())
})
}
return proxy
@@ -131,25 +134,22 @@ object OkHttpClientModule {
@Provides
@Singleton
fun providesCacheDir(@ApplicationContext context: Context): Cache {
return Cache(
directory = File(context.cacheDir, "http_cache"),
maxSize = 100L * 1024 * 1024
)
}
fun providesCacheDir(@ApplicationContext context: Context): Cache = Cache(
directory = File(context.cacheDir, "http_cache"),
maxSize = 100L * 1024 * 1024
)
private fun getGoogleRootCertHashes(context: Context): List<String> {
return try {
val certs = getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca))
certs.map {
val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value)
messageDigest.update(it.publicKey.encoded)
Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
}
} catch (exception: Exception) {
Log.e(TAG, "Failed to get SHA256 certificate hash", exception)
emptyList()
private fun getGoogleRootCertHashes(context: Context): List<String> = try {
val certs =
getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca))
certs.map {
val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value)
messageDigest.update(it.publicKey.encoded)
Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP)
}
} catch (exception: Exception) {
Log.e(TAG, "Failed to get SHA256 certificate hash", exception)
emptyList()
}
private fun getX509Certificates(inputStream: InputStream): List<X509Certificate> {

View File

@@ -78,10 +78,9 @@ class GenericPagingSource<T : Any>(
}
}
override fun getRefreshKey(state: PagingState<Int, T>): Int? {
return state.anchorPosition?.let { anchorPosition ->
override fun getRefreshKey(state: PagingState<Int, T>): Int? =
state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
}

View File

@@ -36,9 +36,8 @@ object AccountProvider {
}
}
fun isLoggedIn(context: Context): Boolean {
return Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN, false)
}
fun isLoggedIn(context: Context): Boolean =
Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN, false)
fun getLoginEmail(context: Context): String? {
val email = Preferences.getString(context, Constants.ACCOUNT_EMAIL_PLAIN)

View File

@@ -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_DISPENSER_URLS
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AuthProvider @Inject constructor(
@@ -70,9 +70,7 @@ class AuthProvider @Inject constructor(
/**
* Checks whether saved AuthData is valid or not
*/
fun isSavedAuthDataValid(): Boolean {
return AuthHelper.isValid(authData!!)
}
fun isSavedAuthDataValid(): Boolean = AuthHelper.isValid(authData!!)
/**
* Builds [AuthData] for login using personal Google account
@@ -94,7 +92,7 @@ class AuthProvider @Inject constructor(
token = token,
tokenType = tokenType,
properties = spoofProvider.deviceProperties,
locale = spoofProvider.locale,
locale = spoofProvider.locale
)
)
} catch (exception: Exception) {
@@ -154,10 +152,15 @@ class AuthProvider @Inject constructor(
private fun throwError(playResponse: PlayResponse, context: Context) {
when (playResponse.code) {
400 -> throw Exception(context.getString(R.string.bad_request))
403 -> throw Exception(context.getString(R.string.access_denied_using_vpn))
404 -> throw Exception(context.getString(R.string.server_unreachable))
429 -> throw Exception(context.getString(R.string.login_rate_limited))
503 -> throw Exception(context.getString(R.string.server_maintenance))
else -> {
if (playResponse.errorString.isNotBlank()) {
throw Exception(playResponse.errorString)

View File

@@ -24,15 +24,15 @@ import android.content.SharedPreferences
import com.aurora.extensions.isNAndAbove
import com.aurora.store.util.Preferences
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.serialization.json.Json
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.serialization.json.Json
@Singleton
class BlacklistProvider @Inject constructor(
private val json: Json,
@ApplicationContext val context: Context,
@ApplicationContext val context: Context
) {
companion object {
@@ -67,19 +67,17 @@ class BlacklistProvider @Inject constructor(
} else {
Preferences.getString(context, PREFERENCE_BLACKLIST)
}
if (rawBlacklist!!.isEmpty())
if (rawBlacklist!!.isEmpty()) {
mutableSetOf()
else
} else {
json.decodeFromString<MutableSet<String>>(rawBlacklist)
}
} catch (e: Exception) {
mutableSetOf()
}
}
fun isBlacklisted(packageName: String): Boolean {
return blacklist.contains(packageName)
}
fun isBlacklisted(packageName: String): Boolean = blacklist.contains(packageName)
fun blacklist(packageName: String) {
blacklist = blacklist.apply {

View File

@@ -41,8 +41,10 @@ object EglExtensionProvider {
val configs = arrayOfNulls<EGLConfig>(configCount[0])
if (egl.eglGetConfigs(display, configs, configCount[0], configCount)) {
val pbufferAttribs = intArrayOf(
EGL10.EGL_WIDTH, EGL10.EGL_PBUFFER_BIT,
EGL10.EGL_HEIGHT, EGL10.EGL_PBUFFER_BIT,
EGL10.EGL_WIDTH,
EGL10.EGL_PBUFFER_BIT,
EGL10.EGL_HEIGHT,
EGL10.EGL_PBUFFER_BIT,
EGL10.EGL_NONE
)
val contextAttributes = intArrayOf(12440, EGL10.EGL_PIXMAP_BIT, EGL10.EGL_NONE)

View File

@@ -30,15 +30,16 @@ object NativeDeviceInfoProvider {
fun getNativeDeviceProperties(context: Context, isExport: Boolean = false): Properties {
val properties = Properties().apply {
//Build Props
// Build Props
setProperty("UserReadableName", "${Build.MANUFACTURER} ${Build.MODEL}")
setProperty("Build.HARDWARE", Build.HARDWARE)
setProperty(
"Build.RADIO",
if (Build.getRadioVersion() != null)
if (Build.getRadioVersion() != null) {
Build.getRadioVersion()
else
} else {
"unknown"
}
)
setProperty("Build.FINGERPRINT", Build.FINGERPRINT)
setProperty("Build.BRAND", Build.BRAND)
@@ -62,21 +63,24 @@ object NativeDeviceInfoProvider {
"${config.navigation == Configuration.NAVIGATIONHIDDEN_YES}"
)
//Display Metrics
// Display Metrics
val metrics = context.resources.displayMetrics
setProperty("Screen.Density", "${metrics.densityDpi}")
setProperty("Screen.Width", "${metrics.widthPixels}")
setProperty("Screen.Height", "${metrics.heightPixels}")
//Supported Platforms
// Supported Platforms
setProperty("Platforms", Build.SUPPORTED_ABIS.joinToString(separator = ","))
//Supported Features
// Supported Features
setProperty("Features", getFeatures(context).joinToString(separator = ","))
//Shared Locales
// Shared Locales
setProperty("Locales", getLocales(context).joinToString(separator = ","))
//Shared Libraries
setProperty("SharedLibraries", getSharedLibraries(context).joinToString(separator = ","))
//GL Extensions
// Shared Libraries
setProperty(
"SharedLibraries",
getSharedLibraries(context).joinToString(separator = ",")
)
// GL Extensions
val activityManager = context.getSystemService<ActivityManager>()
setProperty(
"GL.Version",
@@ -87,7 +91,7 @@ object NativeDeviceInfoProvider {
EglExtensionProvider.eglExtensions.joinToString(separator = ",")
)
//Google Related Props
// Google Related Props
setProperty("Client", "android-google")
val gsfVersionProvider = NativeGsfVersionProvider(context, isExport)
@@ -95,11 +99,11 @@ object NativeDeviceInfoProvider {
setProperty("Vending.version", gsfVersionProvider.vendingVersionCode.toString())
setProperty("Vending.versionString", gsfVersionProvider.vendingVersionString)
//MISC
// MISC
setProperty("Roaming", "mobile-notroaming")
setProperty("TimeZone", "UTC-10")
//Telephony (USA 3650 AT&T)
// Telephony (USA 3650 AT&T)
setProperty("CellOperator", "310")
setProperty("SimOperator", "38")
}
@@ -108,29 +112,23 @@ object NativeDeviceInfoProvider {
return properties
}
private fun getFeatures(context: Context): List<String> {
return context
.packageManager
.systemAvailableFeatures
.mapNotNull { it.name }
}
private fun getFeatures(context: Context): List<String> = context
.packageManager
.systemAvailableFeatures
.mapNotNull { it.name }
private fun getLocales(context: Context): List<String> {
return context
.assets
.locales
.mapNotNull { it.replace("-", "_") }
}
private fun getLocales(context: Context): List<String> = context
.assets
.locales
.mapNotNull { it.replace("-", "_") }
private fun getSharedLibraries(context: Context): List<String> {
return context
.packageManager
.systemSharedLibraryNames
?.toList() ?: emptyList()
}
private fun getSharedLibraries(context: Context): List<String> = context
.packageManager
.systemSharedLibraryNames
?.toList() ?: emptyList()
private fun stripHuaweiProperties(properties: Properties): Properties {
//Add Pixel 7a properties
// Add Pixel 7a properties
properties["Build.HARDWARE"] = "lynx"
properties["Build.BOOTLOADER"] = "lynx-1.0-9716681"
properties["Build.BRAND"] = "google"

View File

@@ -27,12 +27,12 @@ import androidx.core.content.getSystemService
import com.aurora.extensions.isNAndAbove
import com.aurora.store.data.model.NetworkStatus
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import javax.inject.Inject
import javax.inject.Singleton
/**
* A simple provider with a flow to observe internet connectivity changes

View File

@@ -54,8 +54,8 @@ class PermissionProvider(private val fragment: Fragment) :
/**
* Checks whether a known permission has been granted
*/
fun isGranted(context: Context, permissionType: PermissionType): Boolean {
return when (permissionType) {
fun isGranted(context: Context, permissionType: PermissionType): Boolean =
when (permissionType) {
PermissionType.EXTERNAL_STORAGE,
PermissionType.STORAGE_MANAGER -> {
context.isExternalStorageAccessible()
@@ -76,9 +76,8 @@ class PermissionProvider(private val fragment: Fragment) :
PermissionType.DOZE_WHITELIST -> context.isIgnoringBatteryOptimizations()
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
@@ -132,7 +131,9 @@ class PermissionProvider(private val fragment: Fragment) :
Permission(
type = PermissionType.POST_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,
isGranted = isGranted(context, PermissionType.POST_NOTIFICATIONS)
)
@@ -147,7 +148,7 @@ class PermissionProvider(private val fragment: Fragment) :
subtitle = context.getString(R.string.app_links_desc),
optional = true,
isGranted = isGranted(context, PermissionType.APP_LINKS)
),
)
)
}
@@ -195,7 +196,7 @@ class PermissionProvider(private val fragment: Fragment) :
if (!isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS)) {
context.toast(R.string.toast_permission_installer_required)
} else {
/**
/*
* 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,
* even though OS says it is granted.
@@ -231,18 +232,16 @@ class PermissionProvider(private val fragment: Fragment) :
}
@SuppressLint("InlinedApi")
private fun knownPermissions(): Map<PermissionType, Intent> {
return mapOf(
PermissionType.STORAGE_MANAGER to PackageUtil.getStorageManagerIntent(context),
PermissionType.INSTALL_UNKNOWN_APPS to PackageUtil.getInstallUnknownAppsIntent(),
PermissionType.DOZE_WHITELIST to Intent(
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
"package:${BuildConfig.APPLICATION_ID}".toUri()
),
PermissionType.APP_LINKS to Intent(
ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
"package:${BuildConfig.APPLICATION_ID}".toUri()
)
private fun knownPermissions(): Map<PermissionType, Intent> = mapOf(
PermissionType.STORAGE_MANAGER to PackageUtil.getStorageManagerIntent(context),
PermissionType.INSTALL_UNKNOWN_APPS to PackageUtil.getInstallUnknownAppsIntent(),
PermissionType.DOZE_WHITELIST to Intent(
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
"package:${BuildConfig.APPLICATION_ID}".toUri()
),
PermissionType.APP_LINKS to Intent(
ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
"package:${BuildConfig.APPLICATION_ID}".toUri()
)
}
)
}

View File

@@ -137,12 +137,9 @@ open class SpoofDeviceProvider(private val context: Context) {
return File(sourceDir)
}
} catch (ignored: Exception) {
}
return null
}
private fun filenameValid(filename: String): Boolean {
return filename.endsWith(SUFFIX)
}
private fun filenameValid(filename: String): Boolean = filename.endsWith(SUFFIX)
}

View File

@@ -24,11 +24,11 @@ import com.aurora.store.R
import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.serialization.json.Json
import java.util.Locale
import java.util.Properties
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.serialization.json.Json
/**
* Provider class to work with device and locale spoofs
@@ -36,7 +36,7 @@ import javax.inject.Singleton
@Singleton
class SpoofProvider @Inject constructor(
private val json: Json,
@ApplicationContext val context: Context,
@ApplicationContext val context: Context
) : SpoofDeviceProvider(context) {
companion object {
@@ -119,7 +119,10 @@ class SpoofProvider @Inject constructor(
val versionStrings = resources.getStringArray(R.array.pref_vending_version)
currentProperties.setProperty("Vending.version", versionCodes[vendingVersionIndex])
currentProperties.setProperty("Vending.versionString", versionStrings[vendingVersionIndex])
currentProperties.setProperty(
"Vending.versionString",
versionStrings[vendingVersionIndex]
)
}
}
}

View File

@@ -13,9 +13,9 @@ import com.aurora.extensions.TAG
import com.aurora.store.AuroraApp
import com.aurora.store.data.helper.DownloadHelper
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class DownloadCancelReceiver : BroadcastReceiver() {

View File

@@ -64,7 +64,7 @@ class MigrationReceiver : BroadcastReceiver() {
if (CertUtil.isAppGalleryApp(context, context.packageName)) {
val dispensers = Preferences.getStringSet(context, PREFERENCE_DISPENSER_URLS)
.toMutableSet()
dispensers.remove(Constants.URL_DISPENSER)
context.save(PREFERENCE_DISPENSER_URLS, dispensers)
@@ -75,7 +75,8 @@ class MigrationReceiver : BroadcastReceiver() {
// 63 -> 64
if (currentVersion == 2) {
if (isOAndAbove) {
with(context.getSystemService<NotificationManager>()!!) { // !1189
with(context.getSystemService<NotificationManager>()!!) {
// !1189
deleteNotificationChannel("NOTIFICATION_CHANNEL_GENERAL")
deleteNotificationChannel("NOTIFICATION_CHANNEL_ALERT")
}
@@ -87,10 +88,11 @@ class MigrationReceiver : BroadcastReceiver() {
if (currentVersion == 3) {
val updateMode = UpdateMode.entries[
Preferences.getInteger(
context,
PREFERENCE_UPDATES_AUTO,
UpdateMode.DISABLED.ordinal
)]
context,
PREFERENCE_UPDATES_AUTO,
UpdateMode.DISABLED.ordinal
)
]
if (updateMode != UpdateMode.DISABLED) {
runCatching {

View File

@@ -48,7 +48,7 @@ open class PackageManagerReceiver : BroadcastReceiver() {
}
}
//Clear installation queue
// Clear installation queue
appInstaller.getPreferredInstaller().removeFromInstallQueue(packageName)
}
}

View File

@@ -15,15 +15,15 @@ import com.aurora.store.data.helper.DownloadHelper
import com.aurora.store.data.providers.AccountProvider
import com.aurora.store.util.NotificationUtil
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
* Triggers re-install/unarchive of a previously archived app on Android 15+ devices.
*/
@AndroidEntryPoint
class UnarchivePackageReceiver: BroadcastReceiver() {
class UnarchivePackageReceiver : BroadcastReceiver() {
@Inject
lateinit var appDetailsHelper: AppDetailsHelper

View File

@@ -35,7 +35,9 @@ object MigrationHelper {
private fun migrateFrom1To2(database: SupportSQLiteDatabase) {
database.beginTransaction()
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()
} catch (exception: 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) {
database.beginTransaction()
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()
} catch (exception: Exception) {
Log.e(TAG, "Failed while migrating from database version 2 to 3", exception)
@@ -63,7 +67,9 @@ object MigrationHelper {
database.beginTransaction()
try {
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()
} catch (exception: Exception) {
@@ -79,7 +85,9 @@ object MigrationHelper {
private fun migrateFrom4To5(database: SupportSQLiteDatabase) {
database.beginTransaction()
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()
} catch (exception: Exception) {
Log.e(TAG, "Failed while migrating from database version 4 to 5", exception)

View File

@@ -29,25 +29,25 @@ object RoomModule {
fun providesRoomInstance(
@ApplicationContext context: Context,
downloadConverter: DownloadConverter
): AuroraDatabase {
return Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
.addTypeConverter(downloadConverter)
.build()
}
): AuroraDatabase = Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE)
.addMigrations(
MIGRATION_1_2,
MIGRATION_2_3,
MIGRATION_3_4,
MIGRATION_4_5,
MIGRATION_5_6
)
.addTypeConverter(downloadConverter)
.build()
@Provides
fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao {
return auroraDatabase.downloadDao()
}
fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao =
auroraDatabase.downloadDao()
@Provides
fun providesFavouriteDao(auroraDatabase: AuroraDatabase): FavouriteDao {
return auroraDatabase.favouriteDao()
}
fun providesFavouriteDao(auroraDatabase: AuroraDatabase): FavouriteDao =
auroraDatabase.favouriteDao()
@Provides
fun providesUpdateDao(auroraDatabase: AuroraDatabase): UpdateDao {
return auroraDatabase.updateDao()
}
fun providesUpdateDao(auroraDatabase: AuroraDatabase): UpdateDao = auroraDatabase.updateDao()
}

View File

@@ -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.update.Update
import com.aurora.store.util.PathUtil
import kotlinx.parcelize.Parcelize
import java.util.Date
import kotlinx.parcelize.Parcelize
@Parcelize
@Entity(tableName = "download")
@@ -44,73 +44,67 @@ data class Download(
private val isSuccessful get() = status == DownloadStatus.COMPLETED
companion object {
fun fromApp(app: App): Download {
return Download(
app.packageName,
app.versionCode,
app.offerType,
app.isInstalled,
app.displayName,
app.iconArtwork.url,
app.size,
app.id,
DownloadStatus.QUEUED,
0,
0L,
0L,
0,
0,
app.fileList.filterNot { it.url.isBlank() },
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
app.targetSdk,
Date().time,
app.requiresGMS()
)
}
fun fromApp(app: App): Download = Download(
app.packageName,
app.versionCode,
app.offerType,
app.isInstalled,
app.displayName,
app.iconArtwork.url,
app.size,
app.id,
DownloadStatus.QUEUED,
0,
0L,
0L,
0,
0,
app.fileList.filterNot { it.url.isBlank() },
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
app.targetSdk,
Date().time,
app.requiresGMS()
)
fun fromUpdate(update: Update): Download {
return Download(
update.packageName,
update.versionCode,
update.offerType,
true,
update.displayName,
update.iconURL,
update.size,
update.id,
DownloadStatus.QUEUED,
0,
0L,
0L,
0,
0,
update.fileList,
update.sharedLibs,
update.targetSdk,
Date().time
)
}
fun fromUpdate(update: Update): Download = Download(
update.packageName,
update.versionCode,
update.offerType,
true,
update.displayName,
update.iconURL,
update.size,
update.id,
DownloadStatus.QUEUED,
0,
0L,
0L,
0,
0,
update.fileList,
update.sharedLibs,
update.targetSdk,
Date().time
)
fun fromExternalApk(externalApk: ExternalApk): Download {
return Download(
packageName = externalApk.packageName,
versionCode = externalApk.versionCode,
offerType = 0,
isInstalled = false,
displayName = externalApk.displayName,
iconURL = externalApk.iconURL,
size = 0,
id = 0,
status = DownloadStatus.QUEUED,
progress = 0,
speed = 0L,
timeRemaining = 0L,
totalFiles = 1,
downloadedFiles = 0,
fileList = externalApk.fileList,
sharedLibs = emptyList(),
)
}
fun fromExternalApk(externalApk: ExternalApk): Download = Download(
packageName = externalApk.packageName,
versionCode = externalApk.versionCode,
offerType = 0,
isInstalled = false,
displayName = externalApk.displayName,
iconURL = externalApk.iconURL,
size = 0,
id = 0,
status = DownloadStatus.QUEUED,
progress = 0,
speed = 0L,
timeRemaining = 0L,
totalFiles = 1,
downloadedFiles = 0,
fileList = externalApk.fileList,
sharedLibs = emptyList()
)
}
fun canInstall(context: Context): Boolean {

View File

@@ -3,31 +3,25 @@ package com.aurora.store.data.room.download
import androidx.room.ProvidedTypeConverter
import androidx.room.TypeConverter
import com.aurora.gplayapi.data.models.PlayFile
import kotlinx.serialization.json.Json
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.serialization.json.Json
@Singleton
@ProvidedTypeConverter
class DownloadConverter @Inject constructor(private val json: Json) {
@TypeConverter
fun toSharedLibList(string: String): List<SharedLib> {
return json.decodeFromString<List<SharedLib>>(string)
}
fun toSharedLibList(string: String): List<SharedLib> =
json.decodeFromString<List<SharedLib>>(string)
@TypeConverter
fun fromSharedLibList(list: List<SharedLib>): String {
return json.encodeToString(list)
}
fun fromSharedLibList(list: List<SharedLib>): String = json.encodeToString(list)
@TypeConverter
fun toGPlayFileList(string: String): List<PlayFile> {
return json.decodeFromString<List<PlayFile>>(string)
}
fun toGPlayFileList(string: String): List<PlayFile> =
json.decodeFromString<List<PlayFile>>(string)
@TypeConverter
fun fromGPlayFileList(list: List<PlayFile>): String {
return json.encodeToString(list)
}
fun fromGPlayFileList(list: List<PlayFile>): String = json.encodeToString(list)
}

View File

@@ -31,12 +31,7 @@ interface DownloadDao {
WHERE packageName=:packageName
"""
)
suspend fun updateProgress(
packageName: String,
progress: Int,
speed: Long,
timeRemaining: Long
)
suspend fun updateProgress(packageName: String, progress: Int, speed: Long, timeRemaining: Long)
@Query("SELECT * FROM download")
fun downloads(): Flow<List<Download>>

View File

@@ -14,12 +14,10 @@ data class SharedLib(
var fileList: List<PlayFile>
) : Parcelable {
companion object {
fun fromApp(app: App): SharedLib {
return SharedLib(
app.packageName,
app.versionCode,
app.fileList.filterNot { it.url.isBlank() }
)
}
fun fromApp(app: App): SharedLib = SharedLib(
app.packageName,
app.versionCode,
app.fileList.filterNot { it.url.isBlank() }
)
}
}

View File

@@ -21,23 +21,19 @@ data class Favourite(
) : Parcelable {
companion object {
fun fromApp(app: App, mode: Mode): Favourite {
return Favourite(
packageName = app.packageName,
displayName = app.displayName,
iconURL = app.iconArtwork.url,
added = System.currentTimeMillis(),
mode = mode
)
}
fun fromApp(app: App, mode: Mode): Favourite = Favourite(
packageName = app.packageName,
displayName = app.displayName,
iconURL = app.iconArtwork.url,
added = System.currentTimeMillis(),
mode = mode
)
fun Favourite.toApp(): App {
return App(
packageName = packageName,
displayName = displayName,
iconArtwork = Artwork(url = iconURL)
)
}
fun Favourite.toApp(): App = App(
packageName = packageName,
displayName = displayName,
iconArtwork = Artwork(url = iconURL)
)
}
enum class Mode {

View File

@@ -6,5 +6,5 @@ import kotlinx.serialization.Serializable
@Serializable
data class ImportExport(
val favourites: List<Favourite>,
val auroraStoreVersion: Int = BuildConfig.VERSION_CODE,
val auroraStoreVersion: Int = BuildConfig.VERSION_CODE
)

View File

@@ -21,7 +21,5 @@ data class ExternalApk(
var fileList: List<PlayFile>
) : Parcelable {
fun isInstalled(context: Context): Boolean {
return PackageUtil.isInstalled(context, packageName)
}
}
fun isInstalled(context: Context): Boolean = PackageUtil.isInstalled(context, packageName)
}

View File

@@ -33,40 +33,34 @@ data class Update(
) : Parcelable {
companion object {
fun fromApp(context: Context, app: App): Update {
return Update(
app.packageName,
app.versionCode,
app.versionName,
app.displayName,
app.iconArtwork.url,
app.changes,
app.id,
app.developerName,
app.size,
app.updatedOn,
app.certificateSetList.any {
it.certificateSet in CertUtil.getEncodedCertificateHashes(
context, app.packageName
)
},
app.offerType,
app.fileList.filterNot { it.url.isBlank() },
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
app.targetSdk
)
}
fun fromApp(context: Context, app: App): Update = Update(
app.packageName,
app.versionCode,
app.versionName,
app.displayName,
app.iconArtwork.url,
app.changes,
app.id,
app.developerName,
app.size,
app.updatedOn,
app.certificateSetList.any {
it.certificateSet in CertUtil.getEncodedCertificateHashes(
context,
app.packageName
)
},
app.offerType,
app.fileList.filterNot { it.url.isBlank() },
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
app.targetSdk
)
}
fun isSelfUpdate(context: Context): Boolean {
return packageName == context.packageName
}
fun isSelfUpdate(context: Context): Boolean = packageName == context.packageName
fun isInstalled(context: Context): Boolean {
return PackageUtil.isInstalled(context, packageName)
}
fun isInstalled(context: Context): Boolean = PackageUtil.isInstalled(context, packageName)
fun isUpToDate(context: Context): Boolean {
return PackageUtil.isInstalled(context, packageName, versionCode)
}
fun isUpToDate(context: Context): Boolean =
PackageUtil.isInstalled(context, packageName, versionCode)
}

View File

@@ -100,8 +100,8 @@ open class AuthWorker @AssistedInject constructor(
}
}
private suspend fun fetchAuthToken(email: String, oldToken: String? = null): String {
return suspendCoroutine { continuation ->
private suspend fun fetchAuthToken(email: String, oldToken: String? = null): String =
suspendCoroutine { continuation ->
fetchAuthToken(email, oldToken) { future ->
try {
val bundle = future.result
@@ -110,14 +110,15 @@ open class AuthWorker @AssistedInject constructor(
if (token != null) {
continuation.resume(token)
} else {
continuation.resumeWithException(IllegalStateException("Auth token is null"))
continuation.resumeWithException(
IllegalStateException("Auth token is null")
)
}
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}
}
}
private fun fetchAuthToken(
email: String,
@@ -155,8 +156,8 @@ open class AuthWorker @AssistedInject constructor(
}
}
private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType): AuthData? {
return if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) {
private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType): AuthData? =
if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) {
authProvider.saveAuthData(authData)
AccountProvider.login(
context,
@@ -171,5 +172,4 @@ open class AuthWorker @AssistedInject constructor(
AccountProvider.logout(context)
null
}
}
}

View File

@@ -58,19 +58,23 @@ class CacheWorker @AssistedInject constructor(
override suspend fun doWork(): Result {
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")
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
if (download.listFiles().isNullOrEmpty()) {
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()) {
// Purge empty non-accessible directory
Log.i(TAG, "Removing empty directory for ${download.name}, ${versionCode.name}")

View File

@@ -48,9 +48,6 @@ import com.aurora.store.util.PackageUtil
import com.aurora.store.util.PathUtil
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream
import java.net.SocketException
@@ -60,6 +57,9 @@ import java.security.DigestInputStream
import java.security.MessageDigest
import kotlin.coroutines.cancellation.CancellationException
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.
@@ -206,10 +206,13 @@ class DownloadWorker @AssistedInject constructor(
private suspend fun onSuccess(): Result {
return withContext(NonCancellable) {
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)
else
} else {
appInstaller.getPreferredInstaller().install(download)
}
Result.success()
} catch (exception: Exception) {
Log.e(TAG, "Failed to install ${download.packageName}", exception)
@@ -425,7 +428,10 @@ class DownloadWorker @AssistedInject constructor(
}
val notification = NotificationUtil.getDownloadNotification(
context, download, icon, exception?.message
context,
download,
icon,
exception?.message
)
notificationManager.notify(
if (isProgress) NOTIFICATION_ID else download.packageName.hashCode(),
@@ -453,7 +459,10 @@ class DownloadWorker @AssistedInject constructor(
file.inputStream().use { fis ->
DigestInputStream(fis, messageDigest).use { dis ->
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 */
}
}
}

View File

@@ -104,6 +104,7 @@ class ExportWorker @AssistedInject constructor(
notificationManager = context.getSystemService<NotificationManager>()!!
@Suppress("ktlint:standard:mixed-condition-operators")
if (packageName.isNullOrEmpty() || isDownload && versionCode == -1L) {
Log.e(TAG, "Input data is corrupt, bailing out!")
notifyStatus(displayName ?: String(), uri, false)
@@ -126,12 +127,10 @@ class ExportWorker @AssistedInject constructor(
return Result.success()
}
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID_FGS,
NotificationUtil.getExportNotification(context)
)
}
override suspend fun getForegroundInfo(): ForegroundInfo = ForegroundInfo(
NOTIFICATION_ID_FGS,
NotificationUtil.getExportNotification(context)
)
private fun notifyStatus(packageName: String, uri: Uri, success: Boolean = true) {
notificationManager.notify(
@@ -157,12 +156,10 @@ class ExportWorker @AssistedInject constructor(
bundleAllAPKs(fileList.filterNotNull(), uri)
}
private fun copyDownloadedApp(packageName: String, versionCode: Long, uri: Uri) {
return bundleAllAPKs(
PathUtil.getAppDownloadDir(context, packageName, versionCode).listFiles()!!.toList(),
uri
)
}
private fun copyDownloadedApp(packageName: String, versionCode: Long, uri: Uri) = bundleAllAPKs(
PathUtil.getAppDownloadDir(context, packageName, versionCode).listFiles()!!.toList(),
uri
)
/**
* Bundles all the given APKs to a zip file

View File

@@ -32,10 +32,10 @@ import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import java.util.Locale
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.util.Locale
/**
* 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 canSelfUpdate = !CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID) &&
!CertUtil.isAppGalleryApp(context, BuildConfig.APPLICATION_ID) &&
BuildType.CURRENT != BuildType.DEBUG
!CertUtil.isAppGalleryApp(context, BuildConfig.APPLICATION_ID) &&
BuildType.CURRENT != BuildType.DEBUG
private val isAuroraOnlyFilterEnabled: Boolean
get() = Preferences.getBoolean(context, Preferences.PREFERENCE_FILTER_AURORA_ONLY, false)
@@ -77,14 +77,16 @@ class UpdateWorker @AssistedInject constructor(
super.doWork()
Log.i(TAG, "Checking for app updates")
val updateMode = UpdateMode.entries[inputData.getInt(
UpdateHelper.UPDATE_MODE,
Preferences.getInteger(
context,
PREFERENCE_UPDATES_AUTO,
UpdateMode.CHECK_AND_INSTALL.ordinal
val updateMode = UpdateMode.entries[
inputData.getInt(
UpdateHelper.UPDATE_MODE,
Preferences.getInteger(
context,
PREFERENCE_UPDATES_AUTO,
UpdateMode.CHECK_AND_INSTALL.ordinal
)
)
)]
]
if (updateMode == UpdateMode.DISABLED || !AccountProvider.isLoggedIn(context)) {
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
if (updateMode == UpdateMode.CHECK_AND_NOTIFY || !context.isIgnoringBatteryOptimizations()) {
if (updateMode == UpdateMode.CHECK_AND_NOTIFY ||
!context.isIgnoringBatteryOptimizations()
) {
Log.i(TAG, "Found ${updates.size} updates, notifying!")
notifyUpdates(updates)
return Result.success()
@@ -123,7 +127,10 @@ class UpdateWorker @AssistedInject constructor(
// Notify about apps that cannot be auto-updated
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)
}
@@ -137,12 +144,10 @@ class UpdateWorker @AssistedInject constructor(
}
}
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
notificationID,
NotificationUtil.getUpdateNotification(context)
)
}
override suspend fun getForegroundInfo(): ForegroundInfo = ForegroundInfo(
notificationID,
NotificationUtil.getUpdateNotification(context)
)
/**
* Checks and returns updates for all possible apps
@@ -157,12 +162,18 @@ class UpdateWorker @AssistedInject constructor(
val filteredPackages = if (isAuroraOnlyFilterEnabled) {
packages.filter { CertUtil.isAuroraStoreApp(context, it.packageName) }
} 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 { PackageUtil.isUpdatable(context, it.packageName, it.versionCode.toLong()) }
.filter { PackageUtil.isUpdatable(context, it.packageName, it.versionCode) }
.toMutableList()
if (canSelfUpdate) getSelfUpdate()?.let { updates.add(it) }
@@ -179,7 +190,9 @@ class UpdateWorker @AssistedInject constructor(
return withContext(Dispatchers.IO) {
val updateUrl = when (BuildType.CURRENT) {
BuildType.RELEASE -> Constants.UPDATE_URL_STABLE
BuildType.NIGHTLY -> Constants.UPDATE_URL_NIGHTLY
else -> {
Log.i(TAG, "Self-updates are not available for this build!")
return@withContext null
@@ -193,6 +206,7 @@ class UpdateWorker @AssistedInject constructor(
val isUpdate = when (BuildType.CURRENT) {
BuildType.NIGHTLY,
BuildType.RELEASE -> selfUpdate.versionCode > BuildConfig.VERSION_CODE
else -> false
}