Loading app/src/main/java/foundation/e/apps/MainActivity.kt +64 −5 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,12 @@ package foundation.e.apps package foundation.e.apps import android.app.usage.StorageStatsManager import android.os.Build import android.os.Build import android.os.Bundle import android.os.Bundle import android.os.Environment import android.os.StatFs import android.os.storage.StorageManager import android.util.Log import android.util.Log import android.view.View import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity Loading @@ -34,6 +38,7 @@ import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.application.subFrags.ApplicationDialogFragment import foundation.e.apps.application.subFrags.ApplicationDialogFragment import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.workmanager.InstallWorkManager import foundation.e.apps.manager.workmanager.InstallWorkManager import foundation.e.apps.purchase.AppPurchaseFragmentDirections import foundation.e.apps.purchase.AppPurchaseFragmentDirections import foundation.e.apps.setup.signin.SignInViewModel import foundation.e.apps.setup.signin.SignInViewModel Loading @@ -42,6 +47,8 @@ import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.modules.CommonUtilsModule import foundation.e.apps.utils.modules.CommonUtilsModule import kotlinx.coroutines.launch import kotlinx.coroutines.launch import java.io.File import java.util.* @AndroidEntryPoint @AndroidEntryPoint class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() { Loading Loading @@ -161,11 +168,7 @@ class MainActivity : AppCompatActivity() { viewModel.downloadList.observe(this) { list -> viewModel.downloadList.observe(this) { list -> list.forEach { list.forEach { if (it.status == Status.QUEUED) { if (it.status == Status.QUEUED) { lifecycleScope.launch { handleFusedDownloadQueued(it, viewModel) viewModel.updateAwaiting(it) InstallWorkManager.enqueueWork(applicationContext, it) Log.d(TAG, "===> onCreate: AWAITING ${it.name}") } } } } } } } Loading Loading @@ -213,6 +216,27 @@ class MainActivity : AppCompatActivity() { } } } } private fun handleFusedDownloadQueued( it: FusedDownload, viewModel: MainActivityViewModel ) { lifecycleScope.launch { if (!checkStorageAvailability(it)) { showSnackbarMessage(getString(R.string.not_enough_storage)) viewModel.updateUnAvailable(it) return@launch } if (viewModel.internetConnection.value == false) { showNoInternet() viewModel.updateUnAvailable(it) return@launch } viewModel.updateAwaiting(it) InstallWorkManager.enqueueWork(applicationContext, it) Log.d(TAG, "===> onCreate: AWAITING ${it.name}") } } private fun startInstallationOfPurchasedApp( private fun startInstallationOfPurchasedApp( viewModel: MainActivityViewModel, viewModel: MainActivityViewModel, it: String it: String Loading @@ -235,4 +259,39 @@ class MainActivity : AppCompatActivity() { binding.noInternet.visibility = View.VISIBLE binding.noInternet.visibility = View.VISIBLE binding.fragment.visibility = View.GONE binding.fragment.visibility = View.GONE } } // TODO: move storage availability code to FileManager Class private fun checkStorageAvailability(fusedDownload: FusedDownload): Boolean { var availableSpace = 0L availableSpace = calculateAvailableDiskSpace() return availableSpace > fusedDownload.appSize + (500 * (1000 * 1000)) } private fun calculateAvailableDiskSpace(): Long { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val storageManager = getSystemService(STORAGE_SERVICE) as StorageManager val statsManager = getSystemService(STORAGE_STATS_SERVICE) as StorageStatsManager val uuid = storageManager.primaryStorageVolume.uuid try { if (uuid != null) { statsManager.getFreeBytes(UUID.fromString(uuid)) } else { statsManager.getFreeBytes(StorageManager.UUID_DEFAULT) } } catch (e: Exception) { Log.e(TAG, "calculateAvailableDiskSpace: ${e.stackTraceToString()}") getAvailableInternalMemorySize() } } else { getAvailableInternalMemorySize() } } private fun getAvailableInternalMemorySize(): Long { val path: File = Environment.getDataDirectory() val stat = StatFs(path.path) val blockSize = stat.blockSizeLong val availableBlocks = stat.availableBlocksLong return availableBlocks * blockSize } } } app/src/main/java/foundation/e/apps/MainActivityViewModel.kt +8 −2 Original line number Original line Diff line number Diff line Loading @@ -162,7 +162,8 @@ class MainActivityViewModel @Inject constructor( appIcon, appIcon, app.latest_version_code, app.latest_version_code, app.offer_type, app.offer_type, app.isFree app.isFree, app.originalSize ) ) } catch (e: Exception) { } catch (e: Exception) { if (e is ApiException.AppNotPurchased) { if (e is ApiException.AppNotPurchased) { Loading Loading @@ -198,7 +199,8 @@ class MainActivityViewModel @Inject constructor( appIcon, appIcon, app.latest_version_code, app.latest_version_code, app.offer_type, app.offer_type, app.isFree app.isFree, app.originalSize ) ) viewModelScope.launch { viewModelScope.launch { fusedManagerRepository.addFusedDownloadPurchaseNeeded(fusedDownload) fusedManagerRepository.addFusedDownloadPurchaseNeeded(fusedDownload) Loading @@ -210,6 +212,10 @@ class MainActivityViewModel @Inject constructor( fusedManagerRepository.updateAwaiting(fusedDownload) fusedManagerRepository.updateAwaiting(fusedDownload) } } suspend fun updateUnAvailable(fusedDownload: FusedDownload) { fusedManagerRepository.updateUnavailable(fusedDownload) } suspend fun updateAwaitingForPurchasedApp(packageName: String): FusedDownload? { suspend fun updateAwaitingForPurchasedApp(packageName: String): FusedDownload? { val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = packageName) val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = packageName) authData.value?.let { authData.value?.let { Loading app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -639,6 +639,7 @@ class FusedAPIImpl @Inject constructor( offer_type = this.offerType, offer_type = this.offerType, origin = Origin.GPLAY, origin = Origin.GPLAY, shareUrl = this.shareUrl, shareUrl = this.shareUrl, originalSize = this.size, appSize = Formatter.formatFileSize(context, this.size), appSize = Formatter.formatFileSize(context, this.size), isFree = this.isFree, isFree = this.isFree, price = this.price price = this.price Loading app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,7 @@ data class FusedApp( var status: Status = Status.UNAVAILABLE, var status: Status = Status.UNAVAILABLE, var origin: Origin = Origin.CLEANAPK, var origin: Origin = Origin.CLEANAPK, val shareUrl: String = String(), val shareUrl: String = String(), val originalSize: Long = 0, val appSize: String = String(), val appSize: String = String(), var source: String = String(), var source: String = String(), val price: String = String(), val price: String = String(), Loading app/src/main/java/foundation/e/apps/manager/database/fusedDownload/FusedDownload.kt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -20,5 +20,6 @@ data class FusedDownload( val iconByteArray: String = String(), val iconByteArray: String = String(), val versionCode: Int = 1, val versionCode: Int = 1, val offerType: Int = -1, val offerType: Int = -1, val isFree: Boolean = true val isFree: Boolean = true, val appSize: Long = 0 ) ) Loading
app/src/main/java/foundation/e/apps/MainActivity.kt +64 −5 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,12 @@ package foundation.e.apps package foundation.e.apps import android.app.usage.StorageStatsManager import android.os.Build import android.os.Build import android.os.Bundle import android.os.Bundle import android.os.Environment import android.os.StatFs import android.os.storage.StorageManager import android.util.Log import android.util.Log import android.view.View import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity Loading @@ -34,6 +38,7 @@ import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.application.subFrags.ApplicationDialogFragment import foundation.e.apps.application.subFrags.ApplicationDialogFragment import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.workmanager.InstallWorkManager import foundation.e.apps.manager.workmanager.InstallWorkManager import foundation.e.apps.purchase.AppPurchaseFragmentDirections import foundation.e.apps.purchase.AppPurchaseFragmentDirections import foundation.e.apps.setup.signin.SignInViewModel import foundation.e.apps.setup.signin.SignInViewModel Loading @@ -42,6 +47,8 @@ import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.modules.CommonUtilsModule import foundation.e.apps.utils.modules.CommonUtilsModule import kotlinx.coroutines.launch import kotlinx.coroutines.launch import java.io.File import java.util.* @AndroidEntryPoint @AndroidEntryPoint class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() { Loading Loading @@ -161,11 +168,7 @@ class MainActivity : AppCompatActivity() { viewModel.downloadList.observe(this) { list -> viewModel.downloadList.observe(this) { list -> list.forEach { list.forEach { if (it.status == Status.QUEUED) { if (it.status == Status.QUEUED) { lifecycleScope.launch { handleFusedDownloadQueued(it, viewModel) viewModel.updateAwaiting(it) InstallWorkManager.enqueueWork(applicationContext, it) Log.d(TAG, "===> onCreate: AWAITING ${it.name}") } } } } } } } Loading Loading @@ -213,6 +216,27 @@ class MainActivity : AppCompatActivity() { } } } } private fun handleFusedDownloadQueued( it: FusedDownload, viewModel: MainActivityViewModel ) { lifecycleScope.launch { if (!checkStorageAvailability(it)) { showSnackbarMessage(getString(R.string.not_enough_storage)) viewModel.updateUnAvailable(it) return@launch } if (viewModel.internetConnection.value == false) { showNoInternet() viewModel.updateUnAvailable(it) return@launch } viewModel.updateAwaiting(it) InstallWorkManager.enqueueWork(applicationContext, it) Log.d(TAG, "===> onCreate: AWAITING ${it.name}") } } private fun startInstallationOfPurchasedApp( private fun startInstallationOfPurchasedApp( viewModel: MainActivityViewModel, viewModel: MainActivityViewModel, it: String it: String Loading @@ -235,4 +259,39 @@ class MainActivity : AppCompatActivity() { binding.noInternet.visibility = View.VISIBLE binding.noInternet.visibility = View.VISIBLE binding.fragment.visibility = View.GONE binding.fragment.visibility = View.GONE } } // TODO: move storage availability code to FileManager Class private fun checkStorageAvailability(fusedDownload: FusedDownload): Boolean { var availableSpace = 0L availableSpace = calculateAvailableDiskSpace() return availableSpace > fusedDownload.appSize + (500 * (1000 * 1000)) } private fun calculateAvailableDiskSpace(): Long { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val storageManager = getSystemService(STORAGE_SERVICE) as StorageManager val statsManager = getSystemService(STORAGE_STATS_SERVICE) as StorageStatsManager val uuid = storageManager.primaryStorageVolume.uuid try { if (uuid != null) { statsManager.getFreeBytes(UUID.fromString(uuid)) } else { statsManager.getFreeBytes(StorageManager.UUID_DEFAULT) } } catch (e: Exception) { Log.e(TAG, "calculateAvailableDiskSpace: ${e.stackTraceToString()}") getAvailableInternalMemorySize() } } else { getAvailableInternalMemorySize() } } private fun getAvailableInternalMemorySize(): Long { val path: File = Environment.getDataDirectory() val stat = StatFs(path.path) val blockSize = stat.blockSizeLong val availableBlocks = stat.availableBlocksLong return availableBlocks * blockSize } } }
app/src/main/java/foundation/e/apps/MainActivityViewModel.kt +8 −2 Original line number Original line Diff line number Diff line Loading @@ -162,7 +162,8 @@ class MainActivityViewModel @Inject constructor( appIcon, appIcon, app.latest_version_code, app.latest_version_code, app.offer_type, app.offer_type, app.isFree app.isFree, app.originalSize ) ) } catch (e: Exception) { } catch (e: Exception) { if (e is ApiException.AppNotPurchased) { if (e is ApiException.AppNotPurchased) { Loading Loading @@ -198,7 +199,8 @@ class MainActivityViewModel @Inject constructor( appIcon, appIcon, app.latest_version_code, app.latest_version_code, app.offer_type, app.offer_type, app.isFree app.isFree, app.originalSize ) ) viewModelScope.launch { viewModelScope.launch { fusedManagerRepository.addFusedDownloadPurchaseNeeded(fusedDownload) fusedManagerRepository.addFusedDownloadPurchaseNeeded(fusedDownload) Loading @@ -210,6 +212,10 @@ class MainActivityViewModel @Inject constructor( fusedManagerRepository.updateAwaiting(fusedDownload) fusedManagerRepository.updateAwaiting(fusedDownload) } } suspend fun updateUnAvailable(fusedDownload: FusedDownload) { fusedManagerRepository.updateUnavailable(fusedDownload) } suspend fun updateAwaitingForPurchasedApp(packageName: String): FusedDownload? { suspend fun updateAwaitingForPurchasedApp(packageName: String): FusedDownload? { val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = packageName) val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = packageName) authData.value?.let { authData.value?.let { Loading
app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -639,6 +639,7 @@ class FusedAPIImpl @Inject constructor( offer_type = this.offerType, offer_type = this.offerType, origin = Origin.GPLAY, origin = Origin.GPLAY, shareUrl = this.shareUrl, shareUrl = this.shareUrl, originalSize = this.size, appSize = Formatter.formatFileSize(context, this.size), appSize = Formatter.formatFileSize(context, this.size), isFree = this.isFree, isFree = this.isFree, price = this.price price = this.price Loading
app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,7 @@ data class FusedApp( var status: Status = Status.UNAVAILABLE, var status: Status = Status.UNAVAILABLE, var origin: Origin = Origin.CLEANAPK, var origin: Origin = Origin.CLEANAPK, val shareUrl: String = String(), val shareUrl: String = String(), val originalSize: Long = 0, val appSize: String = String(), val appSize: String = String(), var source: String = String(), var source: String = String(), val price: String = String(), val price: String = String(), Loading
app/src/main/java/foundation/e/apps/manager/database/fusedDownload/FusedDownload.kt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -20,5 +20,6 @@ data class FusedDownload( val iconByteArray: String = String(), val iconByteArray: String = String(), val versionCode: Int = 1, val versionCode: Int = 1, val offerType: Int = -1, val offerType: Int = -1, val isFree: Boolean = true val isFree: Boolean = true, val appSize: Long = 0 ) )