Cleanup and retire non-working download options

* External storage download uses external files directory and not the SD card
  to downloads while the description states otherwise. This is in-accurate and
  thus dropped (See #985).

* Custom download path is broken which was implemented as a workaround for the
  above (See #1003).

* Move downloads storage to internal files directory which is sandboxed and only
  accessible to us.

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2024-02-26 14:55:10 +05:30
parent 2f5d39106a
commit caf6dd18c1
59 changed files with 28 additions and 379 deletions

View File

@@ -20,10 +20,8 @@
package com.aurora.store
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.os.Build
import android.os.Bundle
@@ -36,9 +34,7 @@ import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.drawerlayout.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED
import androidx.drawerlayout.widget.DrawerLayout.LOCK_MODE_UNLOCKED
@@ -56,8 +52,6 @@ import com.aurora.Constants
import com.aurora.extensions.accentColor
import com.aurora.extensions.applyThemeAccent
import com.aurora.extensions.isMAndAbove
import com.aurora.extensions.isRAndAbove
import com.aurora.extensions.toast
import com.aurora.store.data.model.NetworkStatus
import com.aurora.store.data.providers.NetworkProvider
import com.aurora.store.databinding.ActivityMainBinding
@@ -76,11 +70,6 @@ class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
private lateinit var appConfig: AppBarConfiguration
private val startForPermissions =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (!it) toast(R.string.permissions_denied)
}
// TopLevelFragments
private val topLevelFrags = listOf(
R.id.appsContainerFragment,
@@ -131,21 +120,6 @@ class MainActivity : AppCompatActivity() {
attachNavigation()
attachDrawer()
/*Check only if download to external storage is enabled*/
if (Preferences.getBoolean(this, Preferences.PREFERENCE_DOWNLOAD_EXTERNAL)) {
if (isRAndAbove()) {
checkExternalStorageManagerPermission()
} else {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
startForPermissions.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
}
// Handle quick exit from back actions
val defaultTab = when (Preferences.getInteger(this, PREFERENCE_DEFAULT_SELECTED_TAB)) {
1 -> R.id.gamesContainerFragment
@@ -212,6 +186,7 @@ class MainActivity : AppCompatActivity() {
navController.navigate(R.id.downloadFragment)
return true
}
R.id.menu_doze_info -> {
navController.navigate(R.id.dozeWarningSheet)
return true

View File

@@ -74,7 +74,7 @@ class SpoofDeviceProvider private constructor(var context: Context) {
private val spoofDevicesFromUser: List<Properties>
get() {
val deviceNames: MutableList<Properties> = ArrayList()
val defaultDir = File(PathUtil.getSpoofDirectory(context))
val defaultDir = PathUtil.getSpoofDirectory(context)
val files = defaultDir.listFiles()
if (defaultDir.exists() && files != null) {
for (file in files) {

View File

@@ -15,7 +15,6 @@ import com.aurora.store.data.room.download.DownloadDao
import com.aurora.store.data.work.DownloadWorker
import com.google.gson.Gson
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.File
import javax.inject.Inject
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
@@ -104,7 +103,7 @@ class DownloadWorkerUtil @Inject constructor(
suspend fun clearAllDownloads() {
Log.i(TAG, "Clearing all downloads!")
downloadDao.deleteAll()
File(PathUtil.getDownloadDirectory(context), "Downloads").deleteRecursively()
PathUtil.getDownloadDirectory(context).deleteRecursively()
}
suspend fun clearFinishedDownloads() {

View File

@@ -21,42 +21,22 @@ package com.aurora.store.util
import android.content.Context
import android.os.Environment
import com.aurora.extensions.isRAndAbove
import java.io.File
import java.util.UUID
import com.aurora.gplayapi.data.models.File as GPlayFile
fun Context.getInternalBaseDirectory(): String {
return (getExternalFilesDir(null) ?: filesDir).path
}
object PathUtil {
private const val libraries = "libraries"
private const val LIBRARIES = "libraries"
private const val DOWNLOADS = "Downloads"
private const val SPOOF = "SpoofConfigs"
fun getDownloadDirectory(context: Context): String {
return if (context.isExternalStorageEnable()) {
getExternalPath(context)
} else {
context.getInternalBaseDirectory()
}
fun getDownloadDirectory(context: Context): File {
return File(context.filesDir, DOWNLOADS)
}
fun getPackageDirectory(context: Context, packageName: String): String {
return getDownloadDirectory(context) + "/Downloads/$packageName"
}
private fun getVersionDirectory(
context: Context,
packageName: String,
versionCode: Int,
sharedLibPackageName: String? = null
): String {
return if (!sharedLibPackageName.isNullOrBlank()) {
getLibDownloadDir(context, packageName, versionCode, sharedLibPackageName).absolutePath
} else {
getPackageDirectory(context, packageName) + "/$versionCode"
}
private fun getPackageDirectory(context: Context, packageName: String): File {
return File(getDownloadDirectory(context), packageName)
}
fun getAppDownloadDir(context: Context, packageName: String, versionCode: Int): File {
@@ -71,7 +51,7 @@ object PathUtil {
): File {
return File(
getAppDownloadDir(context, packageName, versionCode).absolutePath,
"$libraries/$sharedLibPackageName"
"$LIBRARIES/$sharedLibPackageName"
)
}
@@ -82,19 +62,15 @@ object PathUtil {
file: GPlayFile,
sharedLibPackageName: String? = null
): String {
return getVersionDirectory(
context,
packageName,
versionCode,
sharedLibPackageName
) + "/${file.name}"
val downloadDir = if (!sharedLibPackageName.isNullOrBlank()) {
getLibDownloadDir(context, packageName, versionCode, sharedLibPackageName)
} else {
File(getPackageDirectory(context, packageName), versionCode.toString())
}
return File(downloadDir, file.name).absolutePath
}
fun getZipFile(
context: Context,
packageName: String,
versionCode: Int
): File {
fun getZipFile(context: Context, packageName: String, versionCode: Int): File {
return File(
getAppDownloadDir(
context,
@@ -104,67 +80,27 @@ object PathUtil {
)
}
fun getExternalPath(context: Context): String {
val defaultDir =
File("${Environment.getExternalStorageDirectory().absolutePath}/Aurora/Store")
if (!defaultDir.exists())
defaultDir.mkdirs()
return Preferences.getString(
context,
Preferences.PREFERENCE_DOWNLOAD_DIRECTORY,
defaultDir.absolutePath
)
}
private fun getObbDownloadPath(packageName: String): String {
return Environment.getExternalStorageDirectory()
.toString() + "/Android/obb/" + packageName
}
fun getObbDownloadDir(packageName: String): File {
return File(
Environment.getExternalStorageDirectory().absolutePath,
"/Android/obb/$packageName"
)
return File(Environment.getExternalStorageDirectory(), "/Android/obb/$packageName")
}
fun getObbDownloadFile(packageName: String, file: GPlayFile): String {
val obbDir = getObbDownloadPath(packageName)
return "$obbDir/${file.name}"
return File(getObbDownloadDir(packageName), file.name).absolutePath
}
fun needsStorageManagerPerm(fileList: List<GPlayFile>): Boolean {
return fileList.any { it.type == GPlayFile.FileType.OBB || it.type == GPlayFile.FileType.PATCH }
}
fun getSpoofDirectory(context: Context): String {
return "${context.getInternalBaseDirectory()}/SpoofConfigs"
fun getSpoofDirectory(context: Context): File {
return File(context.filesDir, SPOOF)
}
fun getNewEmptySpoofConfig(context: Context): File {
val file = File("${getSpoofDirectory(context)}/${UUID.randomUUID()}.properties")
val file = File(getSpoofDirectory(context), "${UUID.randomUUID()}.properties")
file.parentFile?.mkdirs()
file.createNewFile()
return file
}
fun canWriteToDirectory(context: Context, directoryPath: String): Boolean {
val directory = if (directoryPath.startsWith("/")) {
File(directoryPath)
} else {
File(context.getExternalFilesDir(null), directoryPath)
}
return if (isRAndAbove()) {
Environment.isExternalStorageManager() && directory.exists() && directory.canWrite()
} else {
isExternalStorageAccessible(context) && directory.exists() && directory.canWrite()
}
}
}
fun Context.isExternalStorageEnable(): Boolean {
return Preferences.getBoolean(this, Preferences.PREFERENCE_DOWNLOAD_EXTERNAL)
}

View File

@@ -48,9 +48,6 @@ object Preferences {
const val INSTALLATION_ABANDON_SESSION = "INSTALLATION_ABANDON_SESSION"
const val PREFERENCE_DOWNLOAD_EXTERNAL = "PREFERENCE_DOWNLOAD_EXTERNAL"
const val PREFERENCE_DOWNLOAD_DIRECTORY = "PREFERENCE_DOWNLOAD_DIRECTORY"
const val PREFERENCE_TOS_READ = "PREFERENCE_TOS_READ"
const val PREFERENCE_INSECURE_ANONYMOUS = "PREFERENCE_INSECURE_ANONYMOUS"

View File

@@ -77,7 +77,6 @@ import com.aurora.store.util.PackageUtil
import com.aurora.store.util.PathUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.ShortcutManagerUtil
import com.aurora.store.util.isExternalStorageEnable
import com.aurora.store.view.custom.RatingView
import com.aurora.store.view.epoxy.controller.DetailsCarouselController
import com.aurora.store.view.epoxy.controller.GenericCarouselController
@@ -545,7 +544,7 @@ class AppDetailsFragment : BaseFragment(R.layout.fragment_details) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
updateActionState(State.PROGRESS)
if (PathUtil.needsStorageManagerPerm(app.fileList) || requireContext().isExternalStorageEnable()) {
if (PathUtil.needsStorageManagerPerm(app.fileList)) {
if (isRAndAbove()) {
if (!Environment.isExternalStorageManager()) {
startForStorageManagerResult.launch(

View File

@@ -31,13 +31,10 @@ import com.aurora.extensions.isSAndAbove
import com.aurora.store.R
import com.aurora.store.data.work.UpdateWorker
import com.aurora.store.databinding.FragmentOnboardingBinding
import com.aurora.store.util.PathUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE
import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT
import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB
import com.aurora.store.util.Preferences.PREFERENCE_DOWNLOAD_DIRECTORY
import com.aurora.store.util.Preferences.PREFERENCE_DOWNLOAD_EXTERNAL
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_FDROID
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_GOOGLE
@@ -161,10 +158,6 @@ class OnboardingFragment : Fragment(R.layout.fragment_onboarding) {
save(PREFERENCE_FILTER_GOOGLE, false)
save(PREFERENCE_FILTER_SEARCH, true)
/*Downloader*/
save(PREFERENCE_DOWNLOAD_EXTERNAL, false)
save(PREFERENCE_DOWNLOAD_DIRECTORY, PathUtil.getExternalPath(requireContext()))
/*Network*/
save(PREFERENCE_INSECURE_ANONYMOUS, false)
save(PREFERENCE_PROXY_ENABLED, false)

View File

@@ -19,61 +19,16 @@
package com.aurora.store.view.ui.preferences
import android.Manifest
import android.content.Intent
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.Toolbar
import androidx.navigation.fragment.findNavController
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import com.aurora.extensions.isRAndAbove
import com.aurora.extensions.toast
import com.aurora.store.R
import com.aurora.store.util.PathUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.isExternalStorageAccessible
import com.aurora.store.util.save
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class DownloadPreference : PreferenceFragmentCompat() {
private lateinit var startForStorageManagerResult: ActivityResultLauncher<Intent>
private lateinit var startForPermissions: ActivityResultLauncher<String>
private var downloadDirectoryPreference: Preference? = null
private var downloadExternalPreference: SwitchPreferenceCompat? = null
private var autoDeletePreference: SwitchPreferenceCompat? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startForStorageManagerResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
val state = isRAndAbove() && Environment.isExternalStorageManager()
if (state) {
downloadDirectoryPreference?.summary =
PathUtil.getExternalPath(requireContext())
} else {
notifyPermissionState(isRAndAbove() && Environment.isExternalStorageManager())
}
}
startForPermissions =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (it) {
notifyPermissionState(it)
} else {
downloadExternalPreference?.isChecked = false
}
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences_download, rootKey)
@@ -86,67 +41,5 @@ class DownloadPreference : PreferenceFragmentCompat() {
title = getString(R.string.pref_app_download)
setNavigationOnClickListener { findNavController().navigateUp() }
}
downloadDirectoryPreference = findPreference(Preferences.PREFERENCE_DOWNLOAD_DIRECTORY)
downloadExternalPreference = findPreference(Preferences.PREFERENCE_DOWNLOAD_EXTERNAL)
autoDeletePreference = findPreference(Preferences.PREFERENCE_AUTO_DELETE)
downloadDirectoryPreference?.let { preference ->
preference.summary = PathUtil.getExternalPath(requireContext())
preference.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { it, newValue ->
if (PathUtil.canWriteToDirectory(requireContext(), newValue.toString())) {
it.summary = newValue.toString()
save(Preferences.PREFERENCE_DOWNLOAD_DIRECTORY, newValue.toString())
true
} else {
toast(R.string.pref_download_directory_error)
false
}
}
}
downloadExternalPreference?.let { switchPreferenceCompat ->
switchPreferenceCompat.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, newValue ->
val checked = newValue.toString().toBoolean()
if (checked) {
if (isRAndAbove() && !Environment.isExternalStorageManager()) {
startForStorageManagerResult.launch(
Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
)
}
if (!isRAndAbove() && !isExternalStorageAccessible(requireContext())) {
startForPermissions.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
autoDeletePreference?.let {
if (checked) {
it.isEnabled = true
} else {
it.isEnabled = false
it.isChecked = true
}
}
true
}
}
}
private fun notifyPermissionState(state: Boolean) {
if (state) {
toast(R.string.toast_permission_granted)
} else {
toast(R.string.permissions_denied)
}
}
override fun onDestroy() {
super.onDestroy()
startForStorageManagerResult.unregister()
startForPermissions.unregister()
}
}

View File

@@ -40,7 +40,6 @@ import com.aurora.store.data.event.BusEvent
import com.aurora.store.data.room.download.Download
import com.aurora.store.databinding.FragmentUpdatesBinding
import com.aurora.store.util.PathUtil
import com.aurora.store.util.isExternalStorageEnable
import com.aurora.store.view.epoxy.views.UpdateHeaderViewModel_
import com.aurora.store.view.epoxy.views.app.AppUpdateViewModel_
import com.aurora.store.view.epoxy.views.app.NoAppViewModel_
@@ -203,9 +202,7 @@ class UpdatesFragment : BaseFragment(R.layout.fragment_updates) {
this.app = app
viewModel.updateAllEnqueued = updateAll
if (PathUtil.needsStorageManagerPerm(app.fileList) ||
requireContext().isExternalStorageEnable()
) {
if (PathUtil.needsStorageManagerPerm(app.fileList)) {
if (isRAndAbove()) {
if (!Environment.isExternalStorageManager()) {
startForStorageManagerResult.launch(