diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index 19dfb1935430d6fc1e7148dbe74bd0b24c07a85d..5feaed5a4475c315da2ba0873df24d9ffa344bae 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -30,19 +30,20 @@ InstanceOfCheckForException:GPlayHttpClient.kt$GPlayHttpClient$e is SocketTimeoutException InvalidPackageDeclaration:Trackers.kt$package foundation.e.apps.data.exodus LargeClass:ApplicationFragment.kt$ApplicationFragment : TimeoutFragment + LongParameterList:AppManagerImpl.kt$AppManagerImpl$( @Named("cacheDir") private val cacheDir: String, private val downloadManager: DownloadManager, private val notificationManager: NotificationManager, private val appInstallRepository: AppInstallRepository, private val pwaManager: PWAManager, private val appLoungePackageManager: AppLoungePackageManager, @Named("download") private val downloadNotificationChannel: NotificationChannel, @Named("update") private val updateNotificationChannel: NotificationChannel, @ApplicationContext private val context: Context ) LongParameterList:ApplicationDialogFragment.kt$ApplicationDialogFragment$( title: String, message: String, @DrawableRes drawableResId: Int = -1, drawable: Drawable? = null, positiveButtonText: String = "", positiveButtonAction: (() -> Unit)? = null, cancelButtonText: String = "", cancelButtonAction: (() -> Unit)? = null, cancelable: Boolean = true, onDismissListener: (() -> Unit)? = null, ) LongParameterList:ApplicationListRVAdapter.kt$ApplicationListRVAdapter$( private val applicationInstaller: ApplicationInstaller, private val privacyInfoViewModel: PrivacyInfoViewModel, private val appInfoFetchViewModel: AppInfoFetchViewModel, private val mainActivityViewModel: MainActivityViewModel, private val currentDestinationId: Int, private var lifecycleOwner: LifecycleOwner?, private var paidAppHandler: ((Application) -> Unit)? = null ) LongParameterList:ApplicationViewModel.kt$ApplicationViewModel$( id: String, packageName: String, origin: Origin, isFdroidLink: Boolean, authObjectList: List<AuthObject>, retryBlock: (failedObjects: List<AuthObject>) -> Boolean, ) LongParameterList:CleanApkRetrofit.kt$CleanApkRetrofit$( @Query("keyword") keyword: String, @Query("source") source: String = APP_SOURCE_FOSS, @Query("type") type: String = APP_TYPE_ANY, @Query("nres") nres: Int = 20, @Query("page") page: Int = 1, @Query("by") by: String? = null, ) LongParameterList:EglExtensionProvider.kt$EglExtensionProvider$( egl10: EGL10, eglDisplay: EGLDisplay, eglConfig: EGLConfig?, ai: IntArray, ai1: IntArray?, set: MutableSet<String> ) - LongParameterList:FusedManagerImpl.kt$FusedManagerImpl$( @Named("cacheDir") private val cacheDir: String, private val downloadManager: DownloadManager, private val notificationManager: NotificationManager, private val fusedDownloadRepository: FusedDownloadRepository, private val pwaManager: PWAManager, private val appLoungePackageManager: AppLoungePackageManager, @Named("download") private val downloadNotificationChannel: NotificationChannel, @Named("update") private val updateNotificationChannel: NotificationChannel, @ApplicationContext private val context: Context ) - LongParameterList:MainActivityViewModel.kt$MainActivityViewModel$( private val appLoungeDataStore: AppLoungeDataStore, private val applicationRepository: ApplicationRepository, private val fusedManagerRepository: FusedManagerRepository, private val appLoungePackageManager: AppLoungePackageManager, private val pwaManager: PWAManager, private val ecloudRepository: EcloudRepository, private val blockedAppRepository: BlockedAppRepository, private val appInstallProcessor: AppInstallProcessor, ) + LongParameterList:MainActivityViewModel.kt$MainActivityViewModel$( private val appLoungeDataStore: AppLoungeDataStore, private val applicationRepository: ApplicationRepository, private val appManagerWrapper: AppManagerWrapper, private val appLoungePackageManager: AppLoungePackageManager, private val pwaManager: PWAManager, private val ecloudRepository: EcloudRepository, private val blockedAppRepository: BlockedAppRepository, private val appInstallProcessor: AppInstallProcessor, ) LongParameterList:UpdatesManagerImpl.kt$UpdatesManagerImpl$( @ApplicationContext private val context: Context, private val appLoungePackageManager: AppLoungePackageManager, private val applicationRepository: ApplicationRepository, private val faultyAppRepository: FaultyAppRepository, private val appLoungePreference: AppLoungePreference, private val fdroidRepository: FdroidRepository, private val blockedAppRepository: BlockedAppRepository, ) LongParameterList:UpdatesWorker.kt$UpdatesWorker$( @Assisted private val context: Context, @Assisted private val params: WorkerParameters, private val updatesManagerRepository: UpdatesManagerRepository, private val dataStoreManager: DataStoreManager, private val authenticatorRepository: AuthenticatorRepository, private val appInstallProcessor: AppInstallProcessor, private val blockedAppRepository: BlockedAppRepository, ) MagicNumber:AnonymousLoginManager.kt$AnonymousLoginManager$200 MagicNumber:ApkSignatureManager.kt$ApkSignatureManager$1024 MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$3 MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$4 + MagicNumber:AppManagerWrapper.kt$AppManagerWrapper$100 MagicNumber:ApplicationFragment.kt$ApplicationFragment$100f MagicNumber:ApplicationFragment.kt$ApplicationFragment$15 MagicNumber:ApplicationFragment.kt$ApplicationFragment$3 @@ -64,7 +65,6 @@ MagicNumber:EglExtensionProvider.kt$EglExtensionProvider$4 MagicNumber:EglExtensionProvider.kt$EglExtensionProvider$7939 MagicNumber:FileManager.kt$FileManager$1024 - MagicNumber:FusedManagerRepository.kt$FusedManagerRepository$100 MagicNumber:HomeChildRVAdapter.kt$HomeChildRVAdapter$0.6f MagicNumber:HomeChildRVAdapter.kt$HomeChildRVAdapter$0.7f MagicNumber:HomeChildRVAdapter.kt$HomeChildRVAdapter$500 @@ -80,20 +80,19 @@ MagicNumber:StorageComputer.kt$StorageComputer$500 MagicNumber:StorageComputer.kt$StorageComputer$999950 MagicNumber:TOSFragment.kt$TOSFragment$20 - MaxLineLength:AppInstallProcessor.kt$AppInstallProcessor$"Enqueuing App install work is failed for ${fusedDownload.packageName} exception: ${e.localizedMessage}" + MaxLineLength:AppManagerImpl.kt$AppManagerImpl$. + MaxLineLength:AppManagerImpl.kt$AppManagerImpl$return + MaxLineLength:AppManagerWrapper.kt$AppManagerWrapper$downloadList.find { it.origin == app.origin && (it.packageName == app.package_name || it.id == app.package_name) } + MaxLineLength:AppManagerWrapper.kt$AppManagerWrapper$return fdroidRepository.isFdroidApplicationSigned(context, appInstall.packageName, apkFilePath, appInstall.signature) + MaxLineLength:AppManagerWrapper.kt$AppManagerWrapper$suspend MaxLineLength:AppPrivacyInfo.kt$AppPrivacyInfo MaxLineLength:ApplicationFragment.kt$ApplicationFragment.Companion$"https://gitlab.e.foundation/e/os/apps/-/blob/main/app/src/main/java/foundation/e/apps/data/exodus/repositories/PrivacyScoreRepositoryImpl.kt" MaxLineLength:CommonUtilsModule.kt$CommonUtilsModule$* MaxLineLength:DownloadManager.kt$DownloadManager$Timber.e("Download Issue: $downloadId : DownloadManager returns status: $status but the failed because: reason: $reason") - MaxLineLength:DownloadManagerUtils.kt$DownloadManagerUtils$Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}") + MaxLineLength:DownloadManagerUtils.kt$DownloadManagerUtils$Timber.d("===> updateDownloadStatus: ${appInstall.name}: $downloadId: $numberOfDownloadedItems/${appInstall.downloadIdMap.size}") MaxLineLength:DownloadManagerUtils.kt$DownloadManagerUtils$if - MaxLineLength:DownloadManagerUtils.kt$DownloadManagerUtils$numberOfDownloadedItems == fusedDownload.downloadIdMap.size && numberOfDownloadedItems == fusedDownload.downloadURLList.size + MaxLineLength:DownloadManagerUtils.kt$DownloadManagerUtils$numberOfDownloadedItems == appInstall.downloadIdMap.size && numberOfDownloadedItems == appInstall.downloadURLList.size MaxLineLength:FdroidRepository.kt$FdroidRepository$override suspend - MaxLineLength:FusedManagerImpl.kt$FusedManagerImpl$. - MaxLineLength:FusedManagerImpl.kt$FusedManagerImpl$return - MaxLineLength:FusedManagerRepository.kt$FusedManagerRepository$downloadList.find { it.origin == app.origin && (it.packageName == app.package_name || it.id == app.package_name) } - MaxLineLength:FusedManagerRepository.kt$FusedManagerRepository$return fdroidRepository.isFdroidApplicationSigned(context, fusedDownload.packageName, apkFilePath, fusedDownload.signature) - MaxLineLength:FusedManagerRepository.kt$FusedManagerRepository$suspend MaxLineLength:MainActivity.kt$MainActivity$if MaxLineLength:MainActivityViewModel.kt$MainActivityViewModel$fusedDownload.origin == it.origin && (fusedDownload.packageName == it.package_name || fusedDownload.id == it._id) MaxLineLength:PlayStoreRepository.kt$PlayStoreRepository$suspend fun getSearchResult(query: String, subBundle: MutableSet<SearchBundle.SubBundle>?): Pair<List<App>, MutableSet<SearchBundle.SubBundle>> @@ -115,18 +114,18 @@ ProtectedMemberInFinalClass:GoogleSignInFragment.kt$GoogleSignInFragment$// protected to avoid SyntheticAccessor protected val viewModel: LoginViewModel by lazy { ViewModelProvider(requireActivity())[LoginViewModel::class.java] } ProtectedMemberInFinalClass:SearchFragment.kt$SearchFragment$protected val searchViewModel: SearchViewModel by viewModels() ReturnCount:ApkSignatureManager.kt$ApkSignatureManager$private fun verifyAPKSignature( apkInputStream: BufferedInputStream, apkSignatureInputStream: InputStream, publicKeyInputStream: InputStream, packageName: String ): Boolean - ReturnCount:AppInstallProcessor.kt$AppInstallProcessor$private suspend fun updateDownloadUrls(fusedDownload: FusedDownload): Boolean - ReturnCount:AppInstallProcessor.kt$AppInstallProcessor$suspend fun enqueueFusedDownload( fusedDownload: FusedDownload, isAnUpdate: Boolean = false ) + ReturnCount:AppInstallProcessor.kt$AppInstallProcessor$private suspend fun updateDownloadUrls(appInstall: AppInstall): Boolean + ReturnCount:AppInstallProcessor.kt$AppInstallProcessor$suspend fun enqueueFusedDownload( appInstall: AppInstall, isAnUpdate: Boolean = false ) + ReturnCount:AppManagerWrapper.kt$AppManagerWrapper$suspend fun addDownload(appInstall: AppInstall): Boolean + ReturnCount:AppManagerWrapper.kt$AppManagerWrapper$suspend fun calculateProgress( application: Application?, progress: DownloadProgress ): Int ReturnCount:AppPrivacyInfoRepositoryImpl.kt$AppPrivacyInfoRepositoryImpl$override suspend fun getAppPrivacyInfo( application: Application, appHandle: String ): Result<AppPrivacyInfo> ReturnCount:AppPrivacyInfoRepositoryImpl.kt$AppPrivacyInfoRepositoryImpl$private fun getAppPrivacyInfo( application: Application, appTrackerData: List<Report>, ): AppPrivacyInfo ReturnCount:DownloadManager.kt$DownloadManager$fun getSizeRequired(downloadId: Long): Long ReturnCount:DownloadManager.kt$DownloadManager$private fun sanitizeStatus(downloadId: Long, status: Int, reason: Int): Int ReturnCount:Extensions.kt$fun Context.isNetworkAvailable(): Boolean - ReturnCount:FusedManagerRepository.kt$FusedManagerRepository$suspend fun addDownload(fusedDownload: FusedDownload): Boolean - ReturnCount:FusedManagerRepository.kt$FusedManagerRepository$suspend fun calculateProgress( application: Application?, progress: DownloadProgress ): Int ReturnCount:PlayStoreAuthenticator.kt$PlayStoreAuthenticator$override suspend fun validateAuthData(): ResultSupreme<AuthData?> ReturnCount:PlayStoreAuthenticator.kt$PlayStoreAuthenticator$private suspend fun getAuthDataWithGoogleAccount(): ResultSupreme<AuthData?> - ReturnCount:StorageNotificationManager.kt$StorageNotificationManager$private fun getSpaceMissing(fusedDownload: FusedDownload, downloadId: Long? = null): Long + ReturnCount:StorageNotificationManager.kt$StorageNotificationManager$private fun getSpaceMissing(appInstall: AppInstall, downloadId: Long? = null): Long ReturnCount:UpdatesManagerImpl.kt$UpdatesManagerImpl$private suspend fun calculateSignatureVersion(latestCleanapkApp: Application): String SpreadOperator:DownloadProgressLD.kt$DownloadProgressLD$(*downloadingIds.toLongArray()) SpreadOperator:EglExtensionProvider.kt$EglExtensionProvider$(*`as`) @@ -147,6 +146,7 @@ TooGenericExceptionCaught:AppInfoFetchViewModel.kt$AppInfoFetchViewModel$e: Exception TooGenericExceptionCaught:AppInstallProcessor.kt$AppInstallProcessor$e: Exception TooGenericExceptionCaught:AppLoungePackageManager.kt$AppLoungePackageManager$e: Exception + TooGenericExceptionCaught:AppManagerImpl.kt$AppManagerImpl$e: Exception TooGenericExceptionCaught:ApplicationViewModel.kt$ApplicationViewModel$e: Exception TooGenericExceptionCaught:BlockedAppRepository.kt$BlockedAppRepository$exception: Exception TooGenericExceptionCaught:CommonUtilsModule.kt$CommonUtilsModule$e: Exception @@ -156,7 +156,6 @@ TooGenericExceptionCaught:DownloadProgressLD.kt$DownloadProgressLD$e: Exception TooGenericExceptionCaught:EcloudRepository.kt$EcloudRepository$e: Exception TooGenericExceptionCaught:FileManager.kt$FileManager$e: Exception - TooGenericExceptionCaught:FusedManagerImpl.kt$FusedManagerImpl$e: Exception TooGenericExceptionCaught:GPlayHttpClient.kt$GPlayHttpClient$e: Exception TooGenericExceptionCaught:GoogleLoginManager.kt$GoogleLoginManager$e: Exception TooGenericExceptionCaught:InstallWorkManager.kt$InstallWorkManager$e: Exception @@ -173,12 +172,12 @@ TooGenericExceptionThrown:PlayStoreLoginWrapper.kt$PlayStoreLoginWrapper$throw Exception("Validation network code: ${response.code}") TooGenericExceptionThrown:PlayStoreLoginWrapper.kt$PlayStoreLoginWrapper$throw Exception(error) TooManyFunctions:AppLoungePackageManager.kt$AppLoungePackageManager + TooManyFunctions:AppManager.kt$AppManager + TooManyFunctions:AppManagerImpl.kt$AppManagerImpl : AppManager + TooManyFunctions:AppManagerWrapper.kt$AppManagerWrapper TooManyFunctions:ApplicationListFragment.kt$ApplicationListFragment : TimeoutFragmentApplicationInstaller TooManyFunctions:ApplicationRepository.kt$ApplicationRepository - TooManyFunctions:FusedManagerImpl.kt$FusedManagerImpl : IFusedManager - TooManyFunctions:FusedManagerRepository.kt$FusedManagerRepository TooManyFunctions:HomeFragment.kt$HomeFragment : TimeoutFragmentApplicationInstaller - TooManyFunctions:IFusedManager.kt$IFusedManager TooManyFunctions:MainActivityViewModel.kt$MainActivityViewModel : ViewModel TooManyFunctions:SearchFragment.kt$SearchFragment : TimeoutFragmentOnQueryTextListenerOnSuggestionListenerApplicationInstaller TooManyFunctions:TimeoutFragment.kt$TimeoutFragment : Fragment diff --git a/app/src/main/java/foundation/e/apps/MainActivity.kt b/app/src/main/java/foundation/e/apps/MainActivity.kt index dfc6b776b2bd9a6574db9e88f546b25d9d5bfb87..704d9f030542f2ff6c2307a5fada9551ae70dc4c 100644 --- a/app/src/main/java/foundation/e/apps/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/MainActivity.kt @@ -40,7 +40,7 @@ import com.aurora.gplayapi.exceptions.ApiException import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.LoginViewModel import foundation.e.apps.data.login.PlayStoreAuthenticator @@ -345,11 +345,11 @@ class MainActivity : AppCompatActivity() { EventBus.events.filter { appEvent -> appEvent is AppEvent.AppPurchaseEvent }.collectLatest { - goToAppPurchaseFragment(it.data as FusedDownload) + goToAppPurchaseFragment(it.data as AppInstall) } } - private fun goToAppPurchaseFragment(it: FusedDownload) { + private fun goToAppPurchaseFragment(it: AppInstall) { val action = AppPurchaseFragmentDirections.actionGlobalAppPurchaseFragment(it.packageName) findNavController(R.id.fragment).navigate(action) diff --git a/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt b/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt index a43a4e84136ed33d9407c06ef582ac5e2fc1dddf..30f068df2bd0443c994e0d827f1551be055add05 100644 --- a/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt @@ -38,7 +38,7 @@ import foundation.e.apps.data.application.home.HomeApi import foundation.e.apps.data.application.search.GplaySearchResult import foundation.e.apps.data.application.search.SearchApi import foundation.e.apps.data.application.utils.CategoryType -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.ui.search.SearchResult import javax.inject.Inject import javax.inject.Singleton @@ -87,11 +87,11 @@ class ApplicationRepository @Inject constructor( suspend fun updateFusedDownloadWithDownloadingInfo( origin: Origin, - fusedDownload: FusedDownload + appInstall: AppInstall ) { downloadInfoApi.updateFusedDownloadWithDownloadingInfo( origin, - fusedDownload + appInstall ) } diff --git a/app/src/main/java/foundation/e/apps/data/application/UpdatesDao.kt b/app/src/main/java/foundation/e/apps/data/application/UpdatesDao.kt index e460f1a5de9b125194e4f0ebc8e7bfea5c917613..5b0f58d66192eb5ef8d2422f7b970cb9ec1d4a7b 100644 --- a/app/src/main/java/foundation/e/apps/data/application/UpdatesDao.kt +++ b/app/src/main/java/foundation/e/apps/data/application/UpdatesDao.kt @@ -18,14 +18,14 @@ package foundation.e.apps.data.application import foundation.e.apps.data.application.data.Application -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall object UpdatesDao { private val _appsAwaitingForUpdate: MutableList = mutableListOf() val appsAwaitingForUpdate: List = _appsAwaitingForUpdate - private val _successfulUpdatedApps = mutableListOf() - val successfulUpdatedApps: List = _successfulUpdatedApps + private val _successfulUpdatedApps = mutableListOf() + val successfulUpdatedApps: List = _successfulUpdatedApps fun addItemsForUpdate(appsNeedUpdate: List) { _appsAwaitingForUpdate.clear() @@ -36,8 +36,8 @@ object UpdatesDao { fun removeUpdateIfExists(packageName: String) = _appsAwaitingForUpdate.removeIf { it.package_name == packageName } - fun addSuccessfullyUpdatedApp(fusedDownload: FusedDownload) { - _successfulUpdatedApps.add(fusedDownload) + fun addSuccessfullyUpdatedApp(appInstall: AppInstall) { + _successfulUpdatedApps.add(appInstall) } fun clearSuccessfullyUpdatedApps() { diff --git a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApi.kt b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApi.kt index 3384ea816c5dfc9dbb44326a31e2b2e2b762190a..acfa0a329416f775e19dd7e34487377426735949 100644 --- a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApi.kt +++ b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApi.kt @@ -20,7 +20,7 @@ package foundation.e.apps.data.application.downloadInfo import foundation.e.apps.data.cleanapk.data.download.Download import foundation.e.apps.data.enums.Origin -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import retrofit2.Response interface DownloadInfoApi { @@ -34,7 +34,7 @@ interface DownloadInfoApi { suspend fun updateFusedDownloadWithDownloadingInfo( origin: Origin, - fusedDownload: FusedDownload + appInstall: AppInstall ) suspend fun getOSSDownloadInfo(id: String, version: String?): Response diff --git a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt index 70f817427223b40b1220e6620c1bcd9ae227083f..896510856ea5187641145002b685febf22a26717 100644 --- a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt @@ -21,7 +21,7 @@ package foundation.e.apps.data.application.downloadInfo import foundation.e.apps.data.AppSourcesContainer import foundation.e.apps.data.cleanapk.CleanApkDownloadInfoFetcher import foundation.e.apps.data.enums.Origin -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.handleNetworkResult import javax.inject.Inject @@ -57,45 +57,45 @@ class DownloadInfoApiImpl @Inject constructor( override suspend fun updateFusedDownloadWithDownloadingInfo( origin: Origin, - fusedDownload: FusedDownload + appInstall: AppInstall ) { val list = mutableListOf() when (origin) { Origin.CLEANAPK -> { - updateDownloadInfoFromCleanApk(fusedDownload, list) + updateDownloadInfoFromCleanApk(appInstall, list) } Origin.GPLAY -> { - updateDownloadInfoFromGplay(fusedDownload, list) + updateDownloadInfoFromGplay(appInstall, list) } } - fusedDownload.downloadURLList = list + appInstall.downloadURLList = list } private suspend fun updateDownloadInfoFromGplay( - fusedDownload: FusedDownload, + appInstall: AppInstall, list: MutableList ) { val downloadList = appSources.gplayRepo.getDownloadInfo( - fusedDownload.packageName, - fusedDownload.versionCode, - fusedDownload.offerType + appInstall.packageName, + appInstall.versionCode, + appInstall.offerType ) - fusedDownload.files = downloadList + appInstall.files = downloadList list.addAll(downloadList.map { it.url }) } private suspend fun updateDownloadInfoFromCleanApk( - fusedDownload: FusedDownload, + appInstall: AppInstall, list: MutableList ) { val downloadInfo = (appSources.cleanApkAppsRepo as CleanApkDownloadInfoFetcher) - .getDownloadInfo(fusedDownload.id).body() + .getDownloadInfo(appInstall.id).body() downloadInfo?.download_data?.download_link?.let { list.add(it) } - fusedDownload.signature = downloadInfo?.download_data?.signature ?: "" + appInstall.signature = downloadInfo?.download_data?.signature ?: "" } override suspend fun getOSSDownloadInfo(id: String, version: String?) = diff --git a/app/src/main/java/foundation/e/apps/data/blockedApps/BlockedAppRepository.kt b/app/src/main/java/foundation/e/apps/data/blockedApps/BlockedAppRepository.kt index 9ab06202cf0a92f735dc87e7d1f498c5077528b9..79755cb7eaf5c1f62301678d45f57f82ad563e31 100644 --- a/app/src/main/java/foundation/e/apps/data/blockedApps/BlockedAppRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/blockedApps/BlockedAppRepository.kt @@ -19,7 +19,7 @@ package foundation.e.apps.data.blockedApps import com.google.gson.Gson import foundation.e.apps.data.DownloadManager -import foundation.e.apps.data.fusedDownload.FileManager +import foundation.e.apps.data.install.FileManager import kotlinx.coroutines.suspendCancellableCoroutine import timber.log.Timber import java.io.File diff --git a/app/src/main/java/foundation/e/apps/data/database/fusedDownload/FusedDatabase.kt b/app/src/main/java/foundation/e/apps/data/database/fusedDownload/FusedDatabase.kt deleted file mode 100644 index 4c0a35b77326aab63d5f7e94be897d5641d8b071..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/apps/data/database/fusedDownload/FusedDatabase.kt +++ /dev/null @@ -1,33 +0,0 @@ -package foundation.e.apps.data.database.fusedDownload - -import android.content.Context -import androidx.room.Database -import androidx.room.Room -import androidx.room.RoomDatabase -import androidx.room.TypeConverters -import foundation.e.apps.data.database.AppDatabase -import foundation.e.apps.data.fusedDownload.FusedDownloadDAO -import foundation.e.apps.data.fusedDownload.models.FusedDownload - -@Database(entities = [FusedDownload::class], version = 4, exportSchema = false) -@TypeConverters(FusedConverter::class) -abstract class FusedDatabase : RoomDatabase() { - abstract fun fusedDownloadDao(): FusedDownloadDAO - - companion object { - private lateinit var INSTANCE: FusedDatabase - private const val DATABASE_NAME = "fused_database" - - fun getInstance(context: Context): FusedDatabase { - if (!Companion::INSTANCE.isInitialized) { - synchronized(AppDatabase::class) { - INSTANCE = - Room.databaseBuilder(context, FusedDatabase::class.java, DATABASE_NAME) - .fallbackToDestructiveMigration() - .build() - } - } - return INSTANCE - } - } -} diff --git a/app/src/main/java/foundation/e/apps/data/database/fusedDownload/FusedConverter.kt b/app/src/main/java/foundation/e/apps/data/database/install/AppInstallConverter.kt similarity index 89% rename from app/src/main/java/foundation/e/apps/data/database/fusedDownload/FusedConverter.kt rename to app/src/main/java/foundation/e/apps/data/database/install/AppInstallConverter.kt index 285c0e9450cb8247783c7401c74d93d824993c39..c2bca4df307290f191a110b34ceeefea37ec5d94 100644 --- a/app/src/main/java/foundation/e/apps/data/database/fusedDownload/FusedConverter.kt +++ b/app/src/main/java/foundation/e/apps/data/database/install/AppInstallConverter.kt @@ -1,11 +1,11 @@ -package foundation.e.apps.data.database.fusedDownload +package foundation.e.apps.data.database.install import androidx.room.TypeConverter import com.aurora.gplayapi.data.models.File import com.google.gson.Gson import com.google.gson.reflect.TypeToken -class FusedConverter { +class AppInstallConverter { @TypeConverter fun listToJsonString(value: List): String = Gson().toJson(value) diff --git a/app/src/main/java/foundation/e/apps/data/database/install/AppInstallDatabase.kt b/app/src/main/java/foundation/e/apps/data/database/install/AppInstallDatabase.kt new file mode 100644 index 0000000000000000000000000000000000000000..64f61b27f61a10a7df4d19f32ae5f02207f442ce --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/database/install/AppInstallDatabase.kt @@ -0,0 +1,33 @@ +package foundation.e.apps.data.database.install + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import foundation.e.apps.data.database.AppDatabase +import foundation.e.apps.data.install.AppInstallDAO +import foundation.e.apps.data.install.models.AppInstall + +@Database(entities = [AppInstall::class], version = 4, exportSchema = false) +@TypeConverters(AppInstallConverter::class) +abstract class AppInstallDatabase : RoomDatabase() { + abstract fun fusedDownloadDao(): AppInstallDAO + + companion object { + private lateinit var INSTANCE: AppInstallDatabase + private const val DATABASE_NAME = "fused_database" + + fun getInstance(context: Context): AppInstallDatabase { + if (!Companion::INSTANCE.isInitialized) { + synchronized(AppDatabase::class) { + INSTANCE = + Room.databaseBuilder(context, AppInstallDatabase::class.java, DATABASE_NAME) + .fallbackToDestructiveMigration() + .build() + } + } + return INSTANCE + } + } +} diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedDownloadDAO.kt b/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedDownloadDAO.kt deleted file mode 100644 index 9b3b096efcbaaf421a827c8c0e89e86b68e61de4..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedDownloadDAO.kt +++ /dev/null @@ -1,35 +0,0 @@ -package foundation.e.apps.data.fusedDownload - -import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Update -import foundation.e.apps.data.fusedDownload.models.FusedDownload - -@Dao -interface FusedDownloadDAO { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun addDownload(fusedDownload: FusedDownload) - - @Query("SELECT * FROM fuseddownload") - fun getDownloadLiveList(): LiveData> - - @Query("SELECT * FROM fuseddownload") - suspend fun getDownloadList(): List - - @Query("SELECT * FROM fuseddownload where id = :id") - suspend fun getDownloadById(id: String): FusedDownload? - - @Query("SELECT * FROM fuseddownload where id = :id") - fun getDownloadFlowById(id: String): LiveData - - @Update - suspend fun updateDownload(fusedDownload: FusedDownload) - - @Delete - suspend fun deleteDownload(fusedDownload: FusedDownload) -} diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedDownloadRepository.kt b/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedDownloadRepository.kt deleted file mode 100644 index b15dc8cd4c61d424fe96d1692d5c172131a0489e..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedDownloadRepository.kt +++ /dev/null @@ -1,58 +0,0 @@ -package foundation.e.apps.data.fusedDownload - -import androidx.lifecycle.LiveData -import androidx.lifecycle.asFlow -import foundation.e.apps.OpenForTesting -import foundation.e.apps.data.fusedDownload.models.FusedDownload -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -@OpenForTesting -class FusedDownloadRepository @Inject constructor( - private val fusedDownloadDAO: FusedDownloadDAO -) { - - private val mutex = Mutex() - - suspend fun addDownload(fusedDownload: FusedDownload) { - mutex.withLock { - return fusedDownloadDAO.addDownload(fusedDownload) - } - } - - suspend fun getDownloadList(): List { - mutex.withLock { - return fusedDownloadDAO.getDownloadList() - } - } - - fun getDownloadLiveList(): LiveData> { - return fusedDownloadDAO.getDownloadLiveList() - } - - suspend fun updateDownload(fusedDownload: FusedDownload) { - mutex.withLock { - fusedDownloadDAO.updateDownload(fusedDownload) - } - } - - suspend fun deleteDownload(fusedDownload: FusedDownload) { - mutex.withLock { - return fusedDownloadDAO.deleteDownload(fusedDownload) - } - } - - suspend fun getDownloadById(id: String): FusedDownload? { - mutex.withLock { - return fusedDownloadDAO.getDownloadById(id) - } - } - - fun getDownloadFlowById(id: String): Flow { - return fusedDownloadDAO.getDownloadFlowById(id).asFlow() - } -} diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedManagerImpl.kt b/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedManagerImpl.kt deleted file mode 100644 index f0e2b6b7e36c601960b5522c8e879591f3265029..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedManagerImpl.kt +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright ECORP SAS 2022 - * Apps Quickly and easily install Android apps onto your device! - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package foundation.e.apps.data.fusedDownload - -import android.app.DownloadManager -import android.app.NotificationChannel -import android.app.NotificationManager -import android.content.Context -import android.net.Uri -import android.os.Build -import android.os.Environment -import androidx.annotation.RequiresApi -import androidx.lifecycle.LiveData -import dagger.hilt.android.qualifiers.ApplicationContext -import foundation.e.apps.R -import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.enums.Type -import foundation.e.apps.data.fusedDownload.models.FusedDownload -import foundation.e.apps.install.download.data.DownloadProgressLD -import foundation.e.apps.install.pkg.PWAManager -import foundation.e.apps.install.pkg.AppLoungePackageManager -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import timber.log.Timber -import java.io.File -import javax.inject.Inject -import javax.inject.Named -import javax.inject.Singleton -import com.aurora.gplayapi.data.models.File as AuroraFile - -@Singleton -class FusedManagerImpl @Inject constructor( - @Named("cacheDir") private val cacheDir: String, - private val downloadManager: DownloadManager, - private val notificationManager: NotificationManager, - private val fusedDownloadRepository: FusedDownloadRepository, - private val pwaManager: PWAManager, - private val appLoungePackageManager: AppLoungePackageManager, - @Named("download") private val downloadNotificationChannel: NotificationChannel, - @Named("update") private val updateNotificationChannel: NotificationChannel, - @ApplicationContext private val context: Context -) : IFusedManager { - - private val mutex = Mutex() - - @RequiresApi(Build.VERSION_CODES.O) - override fun createNotificationChannels() { - notificationManager.apply { - createNotificationChannel(downloadNotificationChannel) - createNotificationChannel(updateNotificationChannel) - } - } - - override suspend fun addDownload(fusedDownload: FusedDownload) { - fusedDownload.status = Status.QUEUED - fusedDownloadRepository.addDownload(fusedDownload) - } - - override suspend fun getDownloadById(fusedDownload: FusedDownload): FusedDownload? { - return fusedDownloadRepository.getDownloadById(fusedDownload.id) - } - - override suspend fun getDownloadList(): List { - return fusedDownloadRepository.getDownloadList() - } - - override fun getDownloadLiveList(): LiveData> { - return fusedDownloadRepository.getDownloadLiveList() - } - - @OptIn(DelicateCoroutinesApi::class) - override suspend fun updateDownloadStatus(fusedDownload: FusedDownload, status: Status) { - if (status == Status.INSTALLED) { - fusedDownload.status = status - flushOldDownload(fusedDownload.packageName) - fusedDownloadRepository.deleteDownload(fusedDownload) - } else if (status == Status.INSTALLING) { - fusedDownload.downloadIdMap.all { true } - fusedDownload.status = status - fusedDownloadRepository.updateDownload(fusedDownload) - installApp(fusedDownload) - } - } - - override suspend fun downloadApp(fusedDownload: FusedDownload) { - mutex.withLock { - when (fusedDownload.type) { - Type.NATIVE -> downloadNativeApp(fusedDownload) - Type.PWA -> pwaManager.installPWAApp(fusedDownload) - } - } - } - - override suspend fun installApp(fusedDownload: FusedDownload) { - val list = mutableListOf() - when (fusedDownload.type) { - Type.NATIVE -> { - val parentPathFile = File("$cacheDir/${fusedDownload.packageName}") - parentPathFile.listFiles()?.let { list.addAll(it) } - list.sort() - - if (list.size != 0) { - try { - Timber.i("installApp: STARTED ${fusedDownload.name} ${list.size}") - appLoungePackageManager.installApplication(list, fusedDownload.packageName) - Timber.i("installApp: ENDED ${fusedDownload.name} ${list.size}") - } catch (e: Exception) { - Timber.i(">>> installApp app failed ") - installationIssue(fusedDownload) - throw e - } - } - } - else -> { - Timber.d("Unsupported application type!") - fusedDownload.status = Status.INSTALLATION_ISSUE - fusedDownloadRepository.updateDownload(fusedDownload) - } - } - } - - @OptIn(DelicateCoroutinesApi::class) - override suspend fun cancelDownload(fusedDownload: FusedDownload) { - mutex.withLock { - if (fusedDownload.id.isNotBlank()) { - removeFusedDownload(fusedDownload) - } else { - Timber.d("Unable to cancel download!") - } - } - } - - private suspend fun removeFusedDownload(fusedDownload: FusedDownload) { - fusedDownload.downloadIdMap.forEach { (key, _) -> - downloadManager.remove(key) - } - DownloadProgressLD.setDownloadId(-1) - - if (fusedDownload.status != Status.INSTALLATION_ISSUE) { - fusedDownloadRepository.deleteDownload(fusedDownload) - } - - flushOldDownload(fusedDownload.packageName) - } - - override suspend fun getFusedDownload(downloadId: Long, packageName: String): FusedDownload { - val downloadList = getDownloadList() - var fusedDownload = FusedDownload() - downloadList.forEach { - if (downloadId != 0L) { - if (it.downloadIdMap.contains(downloadId)) { - fusedDownload = it - } - } else if (packageName.isNotBlank()) { - if (it.packageName == packageName) { - fusedDownload = it - } - } - } - return fusedDownload - } - - override fun flushOldDownload(packageName: String) { - val parentPathFile = File("$cacheDir/$packageName") - if (parentPathFile.exists()) parentPathFile.deleteRecursively() - } - - override suspend fun downloadNativeApp(fusedDownload: FusedDownload) { - var count = 0 - var parentPath = "$cacheDir/${fusedDownload.packageName}" - - // Clean old downloads and re-create download dir - flushOldDownload(fusedDownload.packageName) - File(parentPath).mkdirs() - - fusedDownload.status = Status.DOWNLOADING - fusedDownloadRepository.updateDownload(fusedDownload) - DownloadProgressLD.setDownloadId(-1) - fusedDownload.downloadURLList.forEach { - count += 1 - val packagePath: File = if (fusedDownload.files.isNotEmpty()) { - getGplayInstallationPackagePath(fusedDownload, it, parentPath, count) - } else { - File(parentPath, "${fusedDownload.packageName}_$count.apk") - } - val request = DownloadManager.Request(Uri.parse(it)) - .setTitle(if (count == 1) fusedDownload.name else context.getString(R.string.additional_file_for, fusedDownload.name)) - .setDestinationUri(Uri.fromFile(packagePath)) - val requestId = downloadManager.enqueue(request) - DownloadProgressLD.setDownloadId(requestId) - fusedDownload.downloadIdMap[requestId] = false - } - fusedDownloadRepository.updateDownload(fusedDownload) - } - - override fun getGplayInstallationPackagePath( - fusedDownload: FusedDownload, - it: String, - parentPath: String, - count: Int - ): File { - val downloadingFile = fusedDownload.files[fusedDownload.downloadURLList.indexOf(it)] - return if (downloadingFile.type == AuroraFile.FileType.BASE || downloadingFile.type == AuroraFile.FileType.SPLIT) { - File(parentPath, "${fusedDownload.packageName}_$count.apk") - } else { - createObbFileForDownload(fusedDownload, it) - } - } - - override fun createObbFileForDownload( - fusedDownload: FusedDownload, - url: String - ): File { - val parentPath = - context.getExternalFilesDir(null)?.absolutePath + "/Android/obb/" + fusedDownload.packageName - File(parentPath).mkdirs() - val obbFile = fusedDownload.files[fusedDownload.downloadURLList.indexOf(url)] - return File(parentPath, obbFile.name) - } - - override fun moveOBBFilesToOBBDirectory(fusedDownload: FusedDownload) { - fusedDownload.files.forEach { - val parentPath = - context.getExternalFilesDir(null)?.absolutePath + "/Android/obb/" + fusedDownload.packageName - val file = File(parentPath, it.name) - if (file.exists()) { - val destinationDirectory = Environment.getExternalStorageDirectory() - .toString() + "/Android/obb/" + fusedDownload.packageName - File(destinationDirectory).mkdirs() - FileManager.moveFile("$parentPath/", it.name, "$destinationDirectory/") - } - } - } - - override fun getBaseApkPath(fusedDownload: FusedDownload) = - "$cacheDir/${fusedDownload.packageName}/${fusedDownload.packageName}_1.apk" - - override suspend fun installationIssue(fusedDownload: FusedDownload) { - fusedDownload.status = Status.INSTALLATION_ISSUE - fusedDownloadRepository.updateDownload(fusedDownload) - flushOldDownload(fusedDownload.packageName) - } - - override suspend fun updateAwaiting(fusedDownload: FusedDownload) { - fusedDownload.status = Status.AWAITING - fusedDownloadRepository.updateDownload(fusedDownload) - } - - override suspend fun updateUnavailable(fusedDownload: FusedDownload) { - fusedDownload.status = Status.UNAVAILABLE - fusedDownloadRepository.updateDownload(fusedDownload) - } - - override suspend fun updateFusedDownload(fusedDownload: FusedDownload) { - fusedDownloadRepository.updateDownload(fusedDownload) - } - - override suspend fun insertFusedDownloadPurchaseNeeded(fusedDownload: FusedDownload) { - fusedDownload.status = Status.PURCHASE_NEEDED - fusedDownloadRepository.addDownload(fusedDownload) - } - - override fun isFusedDownloadInstalled(fusedDownload: FusedDownload): Boolean { - return appLoungePackageManager.isInstalled(fusedDownload.packageName) - } - - override fun getFusedDownloadInstallationStatus(fusedApp: FusedDownload): Status { - return appLoungePackageManager.getPackageStatus(fusedApp.packageName, fusedApp.versionCode) - } -} diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/IFusedManager.kt b/app/src/main/java/foundation/e/apps/data/fusedDownload/IFusedManager.kt deleted file mode 100644 index 54f7ecb0c02d1f72539661f94e679de6fa4b4ee2..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/IFusedManager.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright MURENA SAS 2023 - * Apps Quickly and easily install Android apps onto your device! - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package foundation.e.apps.data.fusedDownload - -import androidx.lifecycle.LiveData -import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.models.FusedDownload -import java.io.File - -interface IFusedManager { - fun createNotificationChannels() - - suspend fun addDownload(fusedDownload: FusedDownload) - - suspend fun getDownloadById(fusedDownload: FusedDownload): FusedDownload? - - suspend fun getDownloadList(): List - fun getDownloadLiveList(): LiveData> - - suspend fun updateDownloadStatus(fusedDownload: FusedDownload, status: Status) - - suspend fun downloadApp(fusedDownload: FusedDownload) - - suspend fun installApp(fusedDownload: FusedDownload) - - suspend fun cancelDownload(fusedDownload: FusedDownload) - - suspend fun getFusedDownload(downloadId: Long = 0, packageName: String = ""): FusedDownload - fun flushOldDownload(packageName: String) - - suspend fun downloadNativeApp(fusedDownload: FusedDownload) - fun getGplayInstallationPackagePath( - fusedDownload: FusedDownload, - it: String, - parentPath: String, - count: Int - ): File - - fun createObbFileForDownload( - fusedDownload: FusedDownload, - url: String - ): File - - fun moveOBBFilesToOBBDirectory(fusedDownload: FusedDownload) - fun getBaseApkPath(fusedDownload: FusedDownload): String - - suspend fun installationIssue(fusedDownload: FusedDownload) - - suspend fun updateAwaiting(fusedDownload: FusedDownload) - - suspend fun updateUnavailable(fusedDownload: FusedDownload) - - suspend fun updateFusedDownload(fusedDownload: FusedDownload) - - suspend fun insertFusedDownloadPurchaseNeeded(fusedDownload: FusedDownload) - fun isFusedDownloadInstalled(fusedDownload: FusedDownload): Boolean - fun getFusedDownloadInstallationStatus(fusedApp: FusedDownload): Status -} diff --git a/app/src/main/java/foundation/e/apps/data/install/AppInstallDAO.kt b/app/src/main/java/foundation/e/apps/data/install/AppInstallDAO.kt new file mode 100644 index 0000000000000000000000000000000000000000..a68090c2457c9b7d2c452ba418ddef6f6c3a765e --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/install/AppInstallDAO.kt @@ -0,0 +1,35 @@ +package foundation.e.apps.data.install + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update +import foundation.e.apps.data.install.models.AppInstall + +@Dao +interface AppInstallDAO { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun addDownload(appInstall: AppInstall) + + @Query("SELECT * FROM fuseddownload") + fun getDownloadLiveList(): LiveData> + + @Query("SELECT * FROM fuseddownload") + suspend fun getDownloadList(): List + + @Query("SELECT * FROM fuseddownload where id = :id") + suspend fun getDownloadById(id: String): AppInstall? + + @Query("SELECT * FROM fuseddownload where id = :id") + fun getDownloadFlowById(id: String): LiveData + + @Update + suspend fun updateDownload(appInstall: AppInstall) + + @Delete + suspend fun deleteDownload(appInstall: AppInstall) +} diff --git a/app/src/main/java/foundation/e/apps/data/install/AppInstallRepository.kt b/app/src/main/java/foundation/e/apps/data/install/AppInstallRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..30a1d0e6cfc724a9f9029de689a3d8e39f78faa6 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/install/AppInstallRepository.kt @@ -0,0 +1,58 @@ +package foundation.e.apps.data.install + +import androidx.lifecycle.LiveData +import androidx.lifecycle.asFlow +import foundation.e.apps.OpenForTesting +import foundation.e.apps.data.install.models.AppInstall +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +@OpenForTesting +class AppInstallRepository @Inject constructor( + private val appInstallDAO: AppInstallDAO +) { + + private val mutex = Mutex() + + suspend fun addDownload(appInstall: AppInstall) { + mutex.withLock { + return appInstallDAO.addDownload(appInstall) + } + } + + suspend fun getDownloadList(): List { + mutex.withLock { + return appInstallDAO.getDownloadList() + } + } + + fun getDownloadLiveList(): LiveData> { + return appInstallDAO.getDownloadLiveList() + } + + suspend fun updateDownload(appInstall: AppInstall) { + mutex.withLock { + appInstallDAO.updateDownload(appInstall) + } + } + + suspend fun deleteDownload(appInstall: AppInstall) { + mutex.withLock { + return appInstallDAO.deleteDownload(appInstall) + } + } + + suspend fun getDownloadById(id: String): AppInstall? { + mutex.withLock { + return appInstallDAO.getDownloadById(id) + } + } + + fun getDownloadFlowById(id: String): Flow { + return appInstallDAO.getDownloadFlowById(id).asFlow() + } +} diff --git a/app/src/main/java/foundation/e/apps/data/install/AppManager.kt b/app/src/main/java/foundation/e/apps/data/install/AppManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..f479335a420a52f70d17fd4625b1f76a08633658 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/install/AppManager.kt @@ -0,0 +1,74 @@ +/* + * Copyright MURENA SAS 2023 + * Apps Quickly and easily install Android apps onto your device! + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.data.install + +import androidx.lifecycle.LiveData +import foundation.e.apps.data.enums.Status +import foundation.e.apps.data.install.models.AppInstall +import java.io.File + +interface AppManager { + fun createNotificationChannels() + + suspend fun addDownload(appInstall: AppInstall) + + suspend fun getDownloadById(appInstall: AppInstall): AppInstall? + + suspend fun getDownloadList(): List + fun getDownloadLiveList(): LiveData> + + suspend fun updateDownloadStatus(appInstall: AppInstall, status: Status) + + suspend fun downloadApp(appInstall: AppInstall) + + suspend fun installApp(appInstall: AppInstall) + + suspend fun cancelDownload(appInstall: AppInstall) + + suspend fun getFusedDownload(downloadId: Long = 0, packageName: String = ""): AppInstall + fun flushOldDownload(packageName: String) + + suspend fun downloadNativeApp(appInstall: AppInstall) + fun getGplayInstallationPackagePath( + appInstall: AppInstall, + it: String, + parentPath: String, + count: Int + ): File + + fun createObbFileForDownload( + appInstall: AppInstall, + url: String + ): File + + fun moveOBBFilesToOBBDirectory(appInstall: AppInstall) + fun getBaseApkPath(appInstall: AppInstall): String + + suspend fun installationIssue(appInstall: AppInstall) + + suspend fun updateAwaiting(appInstall: AppInstall) + + suspend fun updateUnavailable(appInstall: AppInstall) + + suspend fun updateAppInstall(appInstall: AppInstall) + + suspend fun insertAppInstallPurchaseNeeded(appInstall: AppInstall) + fun isAppInstalled(appInstall: AppInstall): Boolean + fun getInstallationStatus(appInstall: AppInstall): Status +} diff --git a/app/src/main/java/foundation/e/apps/data/install/AppManagerImpl.kt b/app/src/main/java/foundation/e/apps/data/install/AppManagerImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..c857f5c3f9ec490f4070d32d367a9a009850957f --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/install/AppManagerImpl.kt @@ -0,0 +1,287 @@ +/* + * Copyright ECORP SAS 2022 + * Apps Quickly and easily install Android apps onto your device! + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.data.install + +import android.app.DownloadManager +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.net.Uri +import android.os.Build +import android.os.Environment +import androidx.annotation.RequiresApi +import androidx.lifecycle.LiveData +import dagger.hilt.android.qualifiers.ApplicationContext +import foundation.e.apps.R +import foundation.e.apps.data.enums.Status +import foundation.e.apps.data.enums.Type +import foundation.e.apps.data.install.models.AppInstall +import foundation.e.apps.install.download.data.DownloadProgressLD +import foundation.e.apps.install.pkg.PWAManager +import foundation.e.apps.install.pkg.AppLoungePackageManager +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import timber.log.Timber +import java.io.File +import javax.inject.Inject +import javax.inject.Named +import javax.inject.Singleton +import com.aurora.gplayapi.data.models.File as AuroraFile + +@Singleton +class AppManagerImpl @Inject constructor( + @Named("cacheDir") private val cacheDir: String, + private val downloadManager: DownloadManager, + private val notificationManager: NotificationManager, + private val appInstallRepository: AppInstallRepository, + private val pwaManager: PWAManager, + private val appLoungePackageManager: AppLoungePackageManager, + @Named("download") private val downloadNotificationChannel: NotificationChannel, + @Named("update") private val updateNotificationChannel: NotificationChannel, + @ApplicationContext private val context: Context +) : AppManager { + + private val mutex = Mutex() + + @RequiresApi(Build.VERSION_CODES.O) + override fun createNotificationChannels() { + notificationManager.apply { + createNotificationChannel(downloadNotificationChannel) + createNotificationChannel(updateNotificationChannel) + } + } + + override suspend fun addDownload(appInstall: AppInstall) { + appInstall.status = Status.QUEUED + appInstallRepository.addDownload(appInstall) + } + + override suspend fun getDownloadById(appInstall: AppInstall): AppInstall? { + return appInstallRepository.getDownloadById(appInstall.id) + } + + override suspend fun getDownloadList(): List { + return appInstallRepository.getDownloadList() + } + + override fun getDownloadLiveList(): LiveData> { + return appInstallRepository.getDownloadLiveList() + } + + @OptIn(DelicateCoroutinesApi::class) + override suspend fun updateDownloadStatus(appInstall: AppInstall, status: Status) { + if (status == Status.INSTALLED) { + appInstall.status = status + flushOldDownload(appInstall.packageName) + appInstallRepository.deleteDownload(appInstall) + } else if (status == Status.INSTALLING) { + appInstall.downloadIdMap.all { true } + appInstall.status = status + appInstallRepository.updateDownload(appInstall) + installApp(appInstall) + } + } + + override suspend fun downloadApp(appInstall: AppInstall) { + mutex.withLock { + when (appInstall.type) { + Type.NATIVE -> downloadNativeApp(appInstall) + Type.PWA -> pwaManager.installPWAApp(appInstall) + } + } + } + + override suspend fun installApp(appInstall: AppInstall) { + val list = mutableListOf() + when (appInstall.type) { + Type.NATIVE -> { + val parentPathFile = File("$cacheDir/${appInstall.packageName}") + parentPathFile.listFiles()?.let { list.addAll(it) } + list.sort() + + if (list.size != 0) { + try { + Timber.i("installApp: STARTED ${appInstall.name} ${list.size}") + appLoungePackageManager.installApplication(list, appInstall.packageName) + Timber.i("installApp: ENDED ${appInstall.name} ${list.size}") + } catch (e: Exception) { + Timber.i(">>> installApp app failed ") + installationIssue(appInstall) + throw e + } + } + } + else -> { + Timber.d("Unsupported application type!") + appInstall.status = Status.INSTALLATION_ISSUE + appInstallRepository.updateDownload(appInstall) + } + } + } + + @OptIn(DelicateCoroutinesApi::class) + override suspend fun cancelDownload(appInstall: AppInstall) { + mutex.withLock { + if (appInstall.id.isNotBlank()) { + removeFusedDownload(appInstall) + } else { + Timber.d("Unable to cancel download!") + } + } + } + + private suspend fun removeFusedDownload(appInstall: AppInstall) { + appInstall.downloadIdMap.forEach { (key, _) -> + downloadManager.remove(key) + } + DownloadProgressLD.setDownloadId(-1) + + if (appInstall.status != Status.INSTALLATION_ISSUE) { + appInstallRepository.deleteDownload(appInstall) + } + + flushOldDownload(appInstall.packageName) + } + + override suspend fun getFusedDownload(downloadId: Long, packageName: String): AppInstall { + val downloadList = getDownloadList() + var appInstall = AppInstall() + downloadList.forEach { + if (downloadId != 0L) { + if (it.downloadIdMap.contains(downloadId)) { + appInstall = it + } + } else if (packageName.isNotBlank()) { + if (it.packageName == packageName) { + appInstall = it + } + } + } + return appInstall + } + + override fun flushOldDownload(packageName: String) { + val parentPathFile = File("$cacheDir/$packageName") + if (parentPathFile.exists()) parentPathFile.deleteRecursively() + } + + override suspend fun downloadNativeApp(appInstall: AppInstall) { + var count = 0 + var parentPath = "$cacheDir/${appInstall.packageName}" + + // Clean old downloads and re-create download dir + flushOldDownload(appInstall.packageName) + File(parentPath).mkdirs() + + appInstall.status = Status.DOWNLOADING + appInstallRepository.updateDownload(appInstall) + DownloadProgressLD.setDownloadId(-1) + appInstall.downloadURLList.forEach { + count += 1 + val packagePath: File = if (appInstall.files.isNotEmpty()) { + getGplayInstallationPackagePath(appInstall, it, parentPath, count) + } else { + File(parentPath, "${appInstall.packageName}_$count.apk") + } + val request = DownloadManager.Request(Uri.parse(it)) + .setTitle(if (count == 1) appInstall.name else context.getString(R.string.additional_file_for, appInstall.name)) + .setDestinationUri(Uri.fromFile(packagePath)) + val requestId = downloadManager.enqueue(request) + DownloadProgressLD.setDownloadId(requestId) + appInstall.downloadIdMap[requestId] = false + } + appInstallRepository.updateDownload(appInstall) + } + + override fun getGplayInstallationPackagePath( + appInstall: AppInstall, + it: String, + parentPath: String, + count: Int + ): File { + val downloadingFile = appInstall.files[appInstall.downloadURLList.indexOf(it)] + return if (downloadingFile.type == AuroraFile.FileType.BASE || downloadingFile.type == AuroraFile.FileType.SPLIT) { + File(parentPath, "${appInstall.packageName}_$count.apk") + } else { + createObbFileForDownload(appInstall, it) + } + } + + override fun createObbFileForDownload( + appInstall: AppInstall, + url: String + ): File { + val parentPath = + context.getExternalFilesDir(null)?.absolutePath + "/Android/obb/" + appInstall.packageName + File(parentPath).mkdirs() + val obbFile = appInstall.files[appInstall.downloadURLList.indexOf(url)] + return File(parentPath, obbFile.name) + } + + override fun moveOBBFilesToOBBDirectory(appInstall: AppInstall) { + appInstall.files.forEach { + val parentPath = + context.getExternalFilesDir(null)?.absolutePath + "/Android/obb/" + appInstall.packageName + val file = File(parentPath, it.name) + if (file.exists()) { + val destinationDirectory = Environment.getExternalStorageDirectory() + .toString() + "/Android/obb/" + appInstall.packageName + File(destinationDirectory).mkdirs() + FileManager.moveFile("$parentPath/", it.name, "$destinationDirectory/") + } + } + } + + override fun getBaseApkPath(appInstall: AppInstall) = + "$cacheDir/${appInstall.packageName}/${appInstall.packageName}_1.apk" + + override suspend fun installationIssue(appInstall: AppInstall) { + appInstall.status = Status.INSTALLATION_ISSUE + appInstallRepository.updateDownload(appInstall) + flushOldDownload(appInstall.packageName) + } + + override suspend fun updateAwaiting(appInstall: AppInstall) { + appInstall.status = Status.AWAITING + appInstallRepository.updateDownload(appInstall) + } + + override suspend fun updateUnavailable(appInstall: AppInstall) { + appInstall.status = Status.UNAVAILABLE + appInstallRepository.updateDownload(appInstall) + } + + override suspend fun updateAppInstall(appInstall: AppInstall) { + appInstallRepository.updateDownload(appInstall) + } + + override suspend fun insertAppInstallPurchaseNeeded(appInstall: AppInstall) { + appInstall.status = Status.PURCHASE_NEEDED + appInstallRepository.addDownload(appInstall) + } + + override fun isAppInstalled(appInstall: AppInstall): Boolean { + return appLoungePackageManager.isInstalled(appInstall.packageName) + } + + override fun getInstallationStatus(appInstall: AppInstall): Status { + return appLoungePackageManager.getPackageStatus(appInstall.packageName, appInstall.versionCode) + } +} diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedManagerRepository.kt b/app/src/main/java/foundation/e/apps/data/install/AppManagerWrapper.kt similarity index 55% rename from app/src/main/java/foundation/e/apps/data/fusedDownload/FusedManagerRepository.kt rename to app/src/main/java/foundation/e/apps/data/install/AppManagerWrapper.kt index 5134c117d399ac4c4035754816eec880b06b9dfa..7714a8062e31b71b34cab82fd3ba3d113056cda0 100644 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/FusedManagerRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/install/AppManagerWrapper.kt @@ -1,4 +1,4 @@ -package foundation.e.apps.data.fusedDownload +package foundation.e.apps.data.install import android.content.Context import android.os.Build @@ -8,7 +8,7 @@ import foundation.e.apps.OpenForTesting import foundation.e.apps.data.enums.Status import foundation.e.apps.data.fdroid.FdroidRepository import foundation.e.apps.data.application.data.Application -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.install.download.data.DownloadProgress import foundation.e.apps.install.workmanager.InstallWorkManager import javax.inject.Inject @@ -16,27 +16,27 @@ import javax.inject.Singleton @Singleton @OpenForTesting -class FusedManagerRepository @Inject constructor( - private val fusedManagerImpl: IFusedManager, +class AppManagerWrapper @Inject constructor( + private val appManager: AppManager, private val fdroidRepository: FdroidRepository ) { @RequiresApi(Build.VERSION_CODES.O) fun createNotificationChannels() { - return fusedManagerImpl.createNotificationChannels() + return appManager.createNotificationChannels() } - suspend fun downloadApp(fusedDownload: FusedDownload) { - return fusedManagerImpl.downloadApp(fusedDownload) + suspend fun downloadApp(appInstall: AppInstall) { + return appManager.downloadApp(appInstall) } - fun moveOBBFileToOBBDirectory(fusedDownload: FusedDownload) { - return fusedManagerImpl.moveOBBFilesToOBBDirectory(fusedDownload) + fun moveOBBFileToOBBDirectory(appInstall: AppInstall) { + return appManager.moveOBBFilesToOBBDirectory(appInstall) } - suspend fun addDownload(fusedDownload: FusedDownload): Boolean { - val existingFusedDownload = fusedManagerImpl.getDownloadById(fusedDownload) - if (isInstallWorkRunning(existingFusedDownload, fusedDownload)) { + suspend fun addDownload(appInstall: AppInstall): Boolean { + val existingFusedDownload = appManager.getDownloadById(appInstall) + if (isInstallWorkRunning(existingFusedDownload, appInstall)) { return false } @@ -45,67 +45,67 @@ class FusedManagerRepository @Inject constructor( return false } - fusedManagerImpl.addDownload(fusedDownload) + appManager.addDownload(appInstall) return true } - private fun isStatusEligibleToInstall(existingFusedDownload: FusedDownload) = + private fun isStatusEligibleToInstall(existingAppInstall: AppInstall) = listOf( Status.UNAVAILABLE, Status.INSTALLATION_ISSUE, Status.PURCHASE_NEEDED - ).contains(existingFusedDownload.status) + ).contains(existingAppInstall.status) private fun isInstallWorkRunning( - existingFusedDownload: FusedDownload?, - fusedDownload: FusedDownload + existingAppInstall: AppInstall?, + appInstall: AppInstall ) = - existingFusedDownload != null && InstallWorkManager.checkWorkIsAlreadyAvailable( - fusedDownload.id + existingAppInstall != null && InstallWorkManager.checkWorkIsAlreadyAvailable( + appInstall.id ) - suspend fun addFusedDownloadPurchaseNeeded(fusedDownload: FusedDownload) { - fusedManagerImpl.insertFusedDownloadPurchaseNeeded(fusedDownload) + suspend fun addFusedDownloadPurchaseNeeded(appInstall: AppInstall) { + appManager.insertAppInstallPurchaseNeeded(appInstall) } - suspend fun getDownloadList(): List { - return fusedManagerImpl.getDownloadList() + suspend fun getDownloadList(): List { + return appManager.getDownloadList() } - fun getDownloadLiveList(): LiveData> { - return fusedManagerImpl.getDownloadLiveList() + fun getDownloadLiveList(): LiveData> { + return appManager.getDownloadLiveList() } - suspend fun getFusedDownload(downloadId: Long = 0, packageName: String = ""): FusedDownload { - return fusedManagerImpl.getFusedDownload(downloadId, packageName) + suspend fun getFusedDownload(downloadId: Long = 0, packageName: String = ""): AppInstall { + return appManager.getFusedDownload(downloadId, packageName) } - suspend fun updateDownloadStatus(fusedDownload: FusedDownload, status: Status) { - return fusedManagerImpl.updateDownloadStatus(fusedDownload, status) + suspend fun updateDownloadStatus(appInstall: AppInstall, status: Status) { + return appManager.updateDownloadStatus(appInstall, status) } - suspend fun cancelDownload(fusedDownload: FusedDownload) { - return fusedManagerImpl.cancelDownload(fusedDownload) + suspend fun cancelDownload(appInstall: AppInstall) { + return appManager.cancelDownload(appInstall) } - suspend fun installationIssue(fusedDownload: FusedDownload) { - return fusedManagerImpl.installationIssue(fusedDownload) + suspend fun installationIssue(appInstall: AppInstall) { + return appManager.installationIssue(appInstall) } - suspend fun updateAwaiting(fusedDownload: FusedDownload) { - fusedManagerImpl.updateAwaiting(fusedDownload) + suspend fun updateAwaiting(appInstall: AppInstall) { + appManager.updateAwaiting(appInstall) } - suspend fun updateUnavailable(fusedDownload: FusedDownload) { - fusedManagerImpl.updateUnavailable(fusedDownload) + suspend fun updateUnavailable(appInstall: AppInstall) { + appManager.updateUnavailable(appInstall) } - suspend fun updateFusedDownload(fusedDownload: FusedDownload) { - fusedManagerImpl.updateFusedDownload(fusedDownload) + suspend fun updateFusedDownload(appInstall: AppInstall) { + appManager.updateAppInstall(appInstall) } - fun validateFusedDownload(fusedDownload: FusedDownload) = - fusedDownload.packageName.isNotEmpty() && fusedDownload.downloadURLList.isNotEmpty() + fun validateFusedDownload(appInstall: AppInstall) = + appInstall.packageName.isNotEmpty() && appInstall.downloadURLList.isNotEmpty() suspend fun calculateProgress( application: Application?, @@ -174,7 +174,7 @@ class FusedManagerRepository @Inject constructor( return Pair(1, 0) } - fun getDownloadingItemStatus(application: Application?, downloadList: List): Status? { + fun getDownloadingItemStatus(application: Application?, downloadList: List): Status? { application?.let { app -> val downloadingItem = downloadList.find { it.origin == app.origin && (it.packageName == app.package_name || it.id == app.package_name) } @@ -183,16 +183,16 @@ class FusedManagerRepository @Inject constructor( return null } - suspend fun isFdroidApplicationSigned(context: Context, fusedDownload: FusedDownload): Boolean { - val apkFilePath = fusedManagerImpl.getBaseApkPath(fusedDownload) - return fdroidRepository.isFdroidApplicationSigned(context, fusedDownload.packageName, apkFilePath, fusedDownload.signature) + suspend fun isFdroidApplicationSigned(context: Context, appInstall: AppInstall): Boolean { + val apkFilePath = appManager.getBaseApkPath(appInstall) + return fdroidRepository.isFdroidApplicationSigned(context, appInstall.packageName, apkFilePath, appInstall.signature) } - fun isFusedDownloadInstalled(fusedDownload: FusedDownload): Boolean { - return fusedManagerImpl.isFusedDownloadInstalled(fusedDownload) + fun isFusedDownloadInstalled(appInstall: AppInstall): Boolean { + return appManager.isAppInstalled(appInstall) } - fun getFusedDownloadPackageStatus(fusedDownload: FusedDownload): Status { - return fusedManagerImpl.getFusedDownloadInstallationStatus(fusedDownload) + fun getFusedDownloadPackageStatus(appInstall: AppInstall): Status { + return appManager.getInstallationStatus(appInstall) } } diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/FileManager.kt b/app/src/main/java/foundation/e/apps/data/install/FileManager.kt similarity index 96% rename from app/src/main/java/foundation/e/apps/data/fusedDownload/FileManager.kt rename to app/src/main/java/foundation/e/apps/data/install/FileManager.kt index 32a9fab55325f6a618b7d408e98f17f7feca5c31..2c91a163951aab43dbb810303702c285e212d766 100644 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/FileManager.kt +++ b/app/src/main/java/foundation/e/apps/data/install/FileManager.kt @@ -1,4 +1,4 @@ -package foundation.e.apps.data.fusedDownload +package foundation.e.apps.data.install import timber.log.Timber import java.io.File diff --git a/app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt b/app/src/main/java/foundation/e/apps/data/install/models/AppInstall.kt similarity index 90% rename from app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt rename to app/src/main/java/foundation/e/apps/data/install/models/AppInstall.kt index 905d4182b4624ec9f54e0ba9df707cc89fe14412..2d654261881d1cdae4eb62f9ab16ed61acbab408 100644 --- a/app/src/main/java/foundation/e/apps/data/fusedDownload/models/FusedDownload.kt +++ b/app/src/main/java/foundation/e/apps/data/install/models/AppInstall.kt @@ -1,4 +1,4 @@ -package foundation.e.apps.data.fusedDownload.models +package foundation.e.apps.data.install.models import androidx.room.Entity import androidx.room.Ignore @@ -9,8 +9,8 @@ import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.Type -@Entity -data class FusedDownload( +@Entity(tableName = "FusedDownload") +data class AppInstall( @PrimaryKey val id: String = String(), val origin: Origin = Origin.CLEANAPK, var status: Status = Status.UNAVAILABLE, diff --git a/app/src/main/java/foundation/e/apps/di/DatabaseModule.kt b/app/src/main/java/foundation/e/apps/di/DatabaseModule.kt index 63b5cd8f8c9e426cfebdae128416ace6a78961e6..0ede4e137a865d8c3e988bac34c47ed5ed4b35a6 100644 --- a/app/src/main/java/foundation/e/apps/di/DatabaseModule.kt +++ b/app/src/main/java/foundation/e/apps/di/DatabaseModule.kt @@ -6,8 +6,8 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import foundation.e.apps.data.database.fusedDownload.FusedDatabase -import foundation.e.apps.data.fusedDownload.FusedDownloadDAO +import foundation.e.apps.data.database.install.AppInstallDatabase +import foundation.e.apps.data.install.AppInstallDAO import javax.inject.Singleton @Module @@ -15,13 +15,13 @@ import javax.inject.Singleton object DatabaseModule { @Singleton @Provides - fun provideDatabaseInstance(@ApplicationContext context: Context): FusedDatabase { - return FusedDatabase.getInstance(context) + fun provideDatabaseInstance(@ApplicationContext context: Context): AppInstallDatabase { + return AppInstallDatabase.getInstance(context) } @Singleton @Provides - fun provideFusedDaoInstance(fusedDatabase: FusedDatabase): FusedDownloadDAO { - return fusedDatabase.fusedDownloadDao() + fun provideFusedDaoInstance(appInstallDatabase: AppInstallDatabase): AppInstallDAO { + return appInstallDatabase.fusedDownloadDao() } } diff --git a/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt index 4e43c269faa886ce92e1bdbee3926fd6d80df01b..7d548e66a0032888edcb20b4b8680e276bc30946 100644 --- a/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt @@ -28,10 +28,10 @@ import foundation.e.apps.data.exodus.repositories.PrivacyScoreRepository import foundation.e.apps.data.exodus.repositories.PrivacyScoreRepositoryImpl import foundation.e.apps.data.fdroid.FdroidRepository import foundation.e.apps.data.fdroid.IFdroidRepository -import foundation.e.apps.data.fusedDownload.FusedManagerImpl -import foundation.e.apps.data.fusedDownload.IFusedManager import foundation.e.apps.data.playstore.PlayStoreRepository import foundation.e.apps.data.playstore.PlayStoreRepositoryImpl +import foundation.e.apps.data.install.AppManagerImpl +import foundation.e.apps.data.install.AppManager import javax.inject.Singleton @Module @@ -43,7 +43,7 @@ interface RepositoryModule { @Singleton @Binds - fun getFusedManagerImpl(fusedManagerImpl: FusedManagerImpl): IFusedManager + fun getFusedManagerImpl(appManagerImpl: AppManagerImpl): AppManager @Singleton @Binds diff --git a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt index 94e10df97ea8ab0fd4e1910a44e36eaf8f8a506d..2a8a45056e737e0cf3bfb0b2dbc91634a4308ec4 100644 --- a/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt +++ b/app/src/main/java/foundation/e/apps/install/download/DownloadManagerUtils.kt @@ -24,8 +24,8 @@ import foundation.e.apps.R import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.FusedManagerRepository -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppManagerWrapper +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.install.notification.StorageNotificationManager import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus @@ -44,7 +44,7 @@ import javax.inject.Singleton @Singleton class DownloadManagerUtils @Inject constructor( @ApplicationContext private val context: Context, - private val fusedManagerRepository: FusedManagerRepository, + private val appManagerWrapper: AppManagerWrapper, private val downloadManager: DownloadManager, private val storageNotificationManager: StorageNotificationManager, @Named("ioCoroutineScope") private val coroutineScope: CoroutineScope @@ -54,8 +54,8 @@ class DownloadManagerUtils @Inject constructor( @DelicateCoroutinesApi fun cancelDownload(downloadId: Long) { coroutineScope.launch { - val fusedDownload = fusedManagerRepository.getFusedDownload(downloadId) - fusedManagerRepository.cancelDownload(fusedDownload) + val fusedDownload = appManagerWrapper.getFusedDownload(downloadId) + appManagerWrapper.cancelDownload(fusedDownload) } } @@ -64,7 +64,7 @@ class DownloadManagerUtils @Inject constructor( coroutineScope.launch { mutex.withLock { delay(1500) // Waiting for downloadmanager to publish the progress of last bytes - val fusedDownload = fusedManagerRepository.getFusedDownload(downloadId) + val fusedDownload = appManagerWrapper.getFusedDownload(downloadId) if (fusedDownload.id.isNotEmpty()) { if (downloadManager.hasDownloadFailed(downloadId)) { @@ -85,28 +85,28 @@ class DownloadManagerUtils @Inject constructor( } } - private suspend fun handleDownloadSuccess(fusedDownload: FusedDownload) { - Timber.i("===> Download is completed for: ${fusedDownload.name}") - fusedManagerRepository.moveOBBFileToOBBDirectory(fusedDownload) - if (fusedDownload.status == Status.DOWNLOADING) { - fusedDownload.status = Status.DOWNLOADED - fusedManagerRepository.updateFusedDownload(fusedDownload) + private suspend fun handleDownloadSuccess(appInstall: AppInstall) { + Timber.i("===> Download is completed for: ${appInstall.name}") + appManagerWrapper.moveOBBFileToOBBDirectory(appInstall) + if (appInstall.status == Status.DOWNLOADING) { + appInstall.status = Status.DOWNLOADED + appManagerWrapper.updateFusedDownload(appInstall) } } - private suspend fun handleDownloadFailed(fusedDownload: FusedDownload, downloadId: Long) { - fusedManagerRepository.installationIssue(fusedDownload) - fusedManagerRepository.cancelDownload(fusedDownload) - Timber.w("===> Download failed: ${fusedDownload.name} ${fusedDownload.status}") + private suspend fun handleDownloadFailed(appInstall: AppInstall, downloadId: Long) { + appManagerWrapper.installationIssue(appInstall) + appManagerWrapper.cancelDownload(appInstall) + Timber.w("===> Download failed: ${appInstall.name} ${appInstall.status}") if (downloadManager.getDownloadFailureReason(downloadId) == android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE) { - storageNotificationManager.showNotEnoughSpaceNotification(fusedDownload, downloadId) + storageNotificationManager.showNotEnoughSpaceNotification(appInstall, downloadId) EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) } } private suspend fun validateDownload( - fusedDownload: FusedDownload, + appInstall: AppInstall, downloadId: Long ) { val incompleteDownloadState = listOf( @@ -118,21 +118,21 @@ class DownloadManagerUtils @Inject constructor( val isDownloadSuccessful = downloadManager.isDownloadSuccessful(downloadId) if (isDownloadSuccessful.first) { - updateDownloadIdMap(fusedDownload, downloadId) + updateDownloadIdMap(appInstall, downloadId) } val numberOfDownloadedItems = - fusedDownload.downloadIdMap.values.filter { it }.size + appInstall.downloadIdMap.values.filter { it }.size - Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}") + Timber.d("===> updateDownloadStatus: ${appInstall.name}: $downloadId: $numberOfDownloadedItems/${appInstall.downloadIdMap.size}") val areAllFilesDownloaded = areAllFilesDownloaded( numberOfDownloadedItems, - fusedDownload + appInstall ) - if (isDownloadSuccessful.first && areAllFilesDownloaded && checkCleanApkSignatureOK(fusedDownload)) { - handleDownloadSuccess(fusedDownload) + if (isDownloadSuccessful.first && areAllFilesDownloaded && checkCleanApkSignatureOK(appInstall)) { + handleDownloadSuccess(appInstall) return } @@ -142,37 +142,37 @@ class DownloadManagerUtils @Inject constructor( return } - handleDownloadFailed(fusedDownload, downloadId) + handleDownloadFailed(appInstall, downloadId) Timber.e( - "Download failed for ${fusedDownload.packageName}: " + + "Download failed for ${appInstall.packageName}: " + "Download Status: ${isDownloadSuccessful.second}" ) } private fun areAllFilesDownloaded( numberOfDownloadedItems: Int, - fusedDownload: FusedDownload + appInstall: AppInstall ) = - numberOfDownloadedItems == fusedDownload.downloadIdMap.size && numberOfDownloadedItems == fusedDownload.downloadURLList.size + numberOfDownloadedItems == appInstall.downloadIdMap.size && numberOfDownloadedItems == appInstall.downloadURLList.size private suspend fun updateDownloadIdMap( - fusedDownload: FusedDownload, + appInstall: AppInstall, downloadId: Long ) { - fusedDownload.downloadIdMap[downloadId] = true - fusedManagerRepository.updateFusedDownload(fusedDownload) + appInstall.downloadIdMap[downloadId] = true + appManagerWrapper.updateFusedDownload(appInstall) } - private suspend fun checkCleanApkSignatureOK(fusedDownload: FusedDownload): Boolean { - if (fusedDownload.origin != Origin.CLEANAPK || fusedManagerRepository.isFdroidApplicationSigned( - context, fusedDownload + private suspend fun checkCleanApkSignatureOK(appInstall: AppInstall): Boolean { + if (appInstall.origin != Origin.CLEANAPK || appManagerWrapper.isFdroidApplicationSigned( + context, appInstall ) ) { Timber.d("Apk signature is OK") return true } - fusedDownload.status = Status.INSTALLATION_ISSUE - fusedManagerRepository.updateFusedDownload(fusedDownload) + appInstall.status = Status.INSTALLATION_ISSUE + appManagerWrapper.updateFusedDownload(appInstall) Timber.w("CleanApk signature is Wrong!") return false } diff --git a/app/src/main/java/foundation/e/apps/install/download/data/DownloadProgressLD.kt b/app/src/main/java/foundation/e/apps/install/download/data/DownloadProgressLD.kt index 1f6fd60f7b737aa5553def328728ed8f9895997d..d017c2d65964cf601f0d8389b1d2424c9bbb898c 100644 --- a/app/src/main/java/foundation/e/apps/install/download/data/DownloadProgressLD.kt +++ b/app/src/main/java/foundation/e/apps/install/download/data/DownloadProgressLD.kt @@ -27,7 +27,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import foundation.e.apps.data.fusedDownload.FusedManagerRepository +import foundation.e.apps.data.install.AppManagerWrapper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -41,7 +41,7 @@ import kotlin.coroutines.CoroutineContext class DownloadProgressLD @Inject constructor( private val downloadManager: DownloadManager, private val downloadManagerQuery: DownloadManager.Query, - private val fusedManagerRepository: FusedManagerRepository + private val appManagerWrapper: AppManagerWrapper ) : LiveData(), CoroutineScope { private lateinit var job: Job @@ -55,7 +55,7 @@ class DownloadProgressLD @Inject constructor( super.observe(owner, observer) launch { while (hasActiveObservers() || owner.lifecycle.currentState == Lifecycle.State.RESUMED) { - val downloads = fusedManagerRepository.getDownloadList() + val downloads = appManagerWrapper.getDownloadList() val downloadingList = downloads.map { it.downloadIdMap }.filter { it.values.contains(false) } val downloadingIds = mutableListOf() diff --git a/app/src/main/java/foundation/e/apps/install/notification/StorageNotificationManager.kt b/app/src/main/java/foundation/e/apps/install/notification/StorageNotificationManager.kt index cf767bba7d41866d535a9c98590f9cf1ea4dc075..ed467fbf24815d1cfc7bc75da227cb8c30ac0976 100644 --- a/app/src/main/java/foundation/e/apps/install/notification/StorageNotificationManager.kt +++ b/app/src/main/java/foundation/e/apps/install/notification/StorageNotificationManager.kt @@ -29,7 +29,7 @@ import androidx.core.app.NotificationManagerCompat import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.DownloadManager -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.di.NotificationManagerModule import foundation.e.apps.utils.StorageComputer import javax.inject.Inject @@ -42,7 +42,7 @@ class StorageNotificationManager @Inject constructor( const val NOT_ENOUGH_SPACE_NOTIFICATION_ID = 7874 } - fun showNotEnoughSpaceNotification(fusedDownload: FusedDownload, downloadId: Long? = null) { + fun showNotEnoughSpaceNotification(appInstall: AppInstall, downloadId: Long? = null) { with(NotificationManagerCompat.from(context)) { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) @@ -51,7 +51,7 @@ class StorageNotificationManager @Inject constructor( return } - val content = getNotEnoughSpaceNotificationContent(fusedDownload, downloadId) + val content = getNotEnoughSpaceNotificationContent(appInstall, downloadId) notify( NOT_ENOUGH_SPACE_NOTIFICATION_ID, @@ -61,10 +61,10 @@ class StorageNotificationManager @Inject constructor( } private fun getNotEnoughSpaceNotificationContent( - fusedDownload: FusedDownload, + appInstall: AppInstall, downloadId: Long? = null ): String { - val requiredInByte = getSpaceMissing(fusedDownload, downloadId) + val requiredInByte = getSpaceMissing(appInstall, downloadId) if (requiredInByte <= 0L) { return context.getString(R.string.not_enough_storage) @@ -76,9 +76,9 @@ class StorageNotificationManager @Inject constructor( ) } - private fun getSpaceMissing(fusedDownload: FusedDownload, downloadId: Long? = null): Long { - if (fusedDownload.appSize > 0L) { - return calculateSpaceMissingFromFusedDownload(fusedDownload) + private fun getSpaceMissing(appInstall: AppInstall, downloadId: Long? = null): Long { + if (appInstall.appSize > 0L) { + return calculateSpaceMissingFromFusedDownload(appInstall) } if (downloadId == null) { @@ -88,10 +88,10 @@ class StorageNotificationManager @Inject constructor( return downloadManager.getSizeRequired(downloadId) } - private fun calculateSpaceMissingFromFusedDownload(fusedDownload: FusedDownload): Long { - var requiredInByte = StorageComputer.spaceMissing(fusedDownload) + private fun calculateSpaceMissingFromFusedDownload(appInstall: AppInstall): Long { + var requiredInByte = StorageComputer.spaceMissing(appInstall) if (requiredInByte <= 0L) { - requiredInByte = fusedDownload.appSize + requiredInByte = appInstall.appSize } return requiredInByte diff --git a/app/src/main/java/foundation/e/apps/install/pkg/AppLoungePackageManager.kt b/app/src/main/java/foundation/e/apps/install/pkg/AppLoungePackageManager.kt index 04314ee859f9a774c6998452c1d2ddb1c791120b..78da25fa5847c304065ce155b9070083a8b534e1 100644 --- a/app/src/main/java/foundation/e/apps/install/pkg/AppLoungePackageManager.kt +++ b/app/src/main/java/foundation/e/apps/install/pkg/AppLoungePackageManager.kt @@ -36,7 +36,7 @@ import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.Type import foundation.e.apps.data.application.search.SearchApi -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import kotlinx.coroutines.DelicateCoroutinesApi import timber.log.Timber import java.io.File @@ -117,13 +117,13 @@ class AppLoungePackageManager @Inject constructor( * Surrounded by try-catch to prevent exception is case App Lounge and FakeStore's * signing certificate is not the same. */ - fun setFakeStoreAsInstallerIfNeeded(fusedDownload: FusedDownload?) { - if (fusedDownload == null || fusedDownload.packageName.isBlank()) { + fun setFakeStoreAsInstallerIfNeeded(appInstall: AppInstall?) { + if (appInstall == null || appInstall.packageName.isBlank()) { return } - if (fusedDownload.origin == Origin.GPLAY) { - if (fusedDownload.type == Type.NATIVE && isInstalled(FAKE_STORE_PACKAGE_NAME)) { - val targetPackage = fusedDownload.packageName + if (appInstall.origin == Origin.GPLAY) { + if (appInstall.type == Type.NATIVE && isInstalled(FAKE_STORE_PACKAGE_NAME)) { + val targetPackage = appInstall.packageName try { packageManager.setInstallerPackageName(targetPackage, FAKE_STORE_PACKAGE_NAME) Timber.d("Changed installer to $FAKE_STORE_PACKAGE_NAME for $targetPackage") diff --git a/app/src/main/java/foundation/e/apps/install/pkg/InstallerService.kt b/app/src/main/java/foundation/e/apps/install/pkg/InstallerService.kt index 1d98217c79777b9cf69821a22caed53585d81791..e8f40d0a153330f485be79c7c21e922666f4f9d6 100644 --- a/app/src/main/java/foundation/e/apps/install/pkg/InstallerService.kt +++ b/app/src/main/java/foundation/e/apps/install/pkg/InstallerService.kt @@ -25,7 +25,7 @@ import android.os.IBinder import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.faultyApps.FaultyAppRepository import foundation.e.apps.data.application.UpdatesDao -import foundation.e.apps.data.fusedDownload.FusedManagerRepository +import foundation.e.apps.data.install.AppManagerWrapper import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import kotlinx.coroutines.DelicateCoroutinesApi @@ -39,7 +39,7 @@ import javax.inject.Inject class InstallerService : Service() { @Inject - lateinit var fusedManagerRepository: FusedManagerRepository + lateinit var appManagerWrapper: AppManagerWrapper @Inject lateinit var appLoungePackageManager: AppLoungePackageManager @@ -109,8 +109,8 @@ class InstallerService : Service() { Timber.d("updateDownloadStatus: package name should not be empty!") } GlobalScope.launch { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = pkgName) - fusedManagerRepository.installationIssue(fusedDownload) + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = pkgName) + appManagerWrapper.installationIssue(fusedDownload) } } } diff --git a/app/src/main/java/foundation/e/apps/install/pkg/PWAManager.kt b/app/src/main/java/foundation/e/apps/install/pkg/PWAManager.kt index 4b3d37a277ddd36955cd7b37432377c0632eaecf..ccb37248b2107783c78545b7dbb6866d8be0a8d3 100644 --- a/app/src/main/java/foundation/e/apps/install/pkg/PWAManager.kt +++ b/app/src/main/java/foundation/e/apps/install/pkg/PWAManager.kt @@ -15,8 +15,8 @@ import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.OpenForTesting import foundation.e.apps.data.enums.Status import foundation.e.apps.data.application.data.Application -import foundation.e.apps.data.fusedDownload.FusedDownloadRepository -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppInstallRepository +import foundation.e.apps.data.install.models.AppInstall import kotlinx.coroutines.delay import timber.log.Timber import java.io.ByteArrayOutputStream @@ -29,7 +29,7 @@ import javax.inject.Singleton @OpenForTesting class PWAManager @Inject constructor( @ApplicationContext private val context: Context, - private val fusedDownloadRepository: FusedDownloadRepository, + private val appInstallRepository: AppInstallRepository, ) { companion object { @@ -111,32 +111,32 @@ class PWAManager @Inject constructor( context.startActivity(launchIntent) } - suspend fun installPWAApp(fusedDownload: FusedDownload) { + suspend fun installPWAApp(appInstall: AppInstall) { // Update status - fusedDownload.status = Status.DOWNLOADING - fusedDownloadRepository.updateDownload(fusedDownload) + appInstall.status = Status.DOWNLOADING + appInstallRepository.updateDownload(appInstall) // Get bitmap and byteArray for icon - val iconBitmap = getIconImageBitmap(fusedDownload.getAppIconUrl()) + val iconBitmap = getIconImageBitmap(appInstall.getAppIconUrl()) if (iconBitmap == null) { - fusedDownload.status = Status.INSTALLATION_ISSUE - fusedDownloadRepository.updateDownload(fusedDownload) + appInstall.status = Status.INSTALLATION_ISSUE + appInstallRepository.updateDownload(appInstall) return } val iconByteArray = iconBitmap.toByteArray() val values = ContentValues() values.apply { - put(URL, fusedDownload.downloadURLList[0]) - put(SHORTCUT_ID, fusedDownload.id) - put(TITLE, fusedDownload.name) + put(URL, appInstall.downloadURLList[0]) + put(SHORTCUT_ID, appInstall.id) + put(TITLE, appInstall.name) put(ICON, iconByteArray) } context.contentResolver.insert(Uri.parse(PWA_PLAYER), values)?.let { val databaseID = ContentUris.parseId(it) - publishShortcut(fusedDownload, iconBitmap, databaseID) + publishShortcut(appInstall, iconBitmap, databaseID) } } @@ -157,25 +157,25 @@ class PWAManager @Inject constructor( } private suspend fun publishShortcut( - fusedDownload: FusedDownload, + appInstall: AppInstall, bitmap: Bitmap, databaseID: Long ) { // Update status - fusedDownload.status = Status.INSTALLING - fusedDownloadRepository.updateDownload(fusedDownload) + appInstall.status = Status.INSTALLING + appInstallRepository.updateDownload(appInstall) val intent = Intent().apply { action = VIEW_PWA - data = Uri.parse(fusedDownload.downloadURLList[0]) - putExtra(PWA_NAME, fusedDownload.name) + data = Uri.parse(appInstall.downloadURLList[0]) + putExtra(PWA_NAME, appInstall.name) putExtra(PWA_ID, databaseID) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) } - val shortcutInfo = ShortcutInfoCompat.Builder(context, fusedDownload.id) - .setShortLabel(fusedDownload.name) + val shortcutInfo = ShortcutInfoCompat.Builder(context, appInstall.id) + .setShortLabel(appInstall.name) .setIcon(IconCompat.createWithBitmap(bitmap)) .setIntent(intent) .build() @@ -185,9 +185,9 @@ class PWAManager @Inject constructor( delay(DELAY_100) // Update status - fusedDownload.status = Status.INSTALLED - fusedDownloadRepository.updateDownload(fusedDownload) + appInstall.status = Status.INSTALLED + appInstallRepository.updateDownload(appInstall) delay(DELAY_500) - fusedDownloadRepository.deleteDownload(fusedDownload) + appInstallRepository.deleteDownload(appInstall) } } diff --git a/app/src/main/java/foundation/e/apps/install/pkg/PackageInstallerService.kt b/app/src/main/java/foundation/e/apps/install/pkg/PackageInstallerService.kt index fc9e38f72c33748ff7d0feb678def517317b2643..ae0e59633dcc7df00585c4191aa7d1adfd9a17b1 100644 --- a/app/src/main/java/foundation/e/apps/install/pkg/PackageInstallerService.kt +++ b/app/src/main/java/foundation/e/apps/install/pkg/PackageInstallerService.kt @@ -24,7 +24,7 @@ import android.content.pm.PackageInstaller import android.os.IBinder import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.FusedManagerRepository +import foundation.e.apps.data.install.AppManagerWrapper import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -36,7 +36,7 @@ import javax.inject.Inject class PackageInstallerService : Service() { @Inject - lateinit var fusedManagerRepository: FusedManagerRepository + lateinit var appManagerWrapper: AppManagerWrapper override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -69) @@ -63,15 +63,15 @@ class PackageInstallerService : Service() { // TODO: FIND A BETTER WAY TO DO THIS private fun updateDownloadStatus(pkgName: String) { GlobalScope.launch { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = pkgName) - fusedManagerRepository.updateDownloadStatus(fusedDownload, Status.INSTALLED) + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = pkgName) + appManagerWrapper.updateDownloadStatus(fusedDownload, Status.INSTALLED) } } private fun updateInstallationIssue(pkgName: String) { GlobalScope.launch { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = pkgName) - fusedManagerRepository.installationIssue(fusedDownload) + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = pkgName) + appManagerWrapper.installationIssue(fusedDownload) } } } diff --git a/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerBR.kt b/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerBR.kt index 29cb4dfc1cc06226c6f54bd6244018de5ab8e1e6..515b2703661176b78477dcce6b4a3827a69da3ca 100644 --- a/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerBR.kt +++ b/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerBR.kt @@ -25,7 +25,7 @@ import android.content.pm.PackageInstaller import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.enums.Status import foundation.e.apps.data.faultyApps.FaultyAppRepository -import foundation.e.apps.data.fusedDownload.FusedManagerRepository +import foundation.e.apps.data.install.AppManagerWrapper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope @@ -39,7 +39,7 @@ import javax.inject.Named open class PkgManagerBR : BroadcastReceiver() { @Inject - lateinit var fusedManagerRepository: FusedManagerRepository + lateinit var appManagerWrapper: AppManagerWrapper @Inject lateinit var appLoungePackageManager: AppLoungePackageManager @@ -102,8 +102,8 @@ open class PkgManagerBR : BroadcastReceiver() { private fun deleteDownload(pkgName: String) { GlobalScope.launch { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = pkgName) - fusedManagerRepository.cancelDownload(fusedDownload) + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = pkgName) + appManagerWrapper.cancelDownload(fusedDownload) } } @@ -113,16 +113,16 @@ open class PkgManagerBR : BroadcastReceiver() { Timber.d("updateDownloadStatus: package name should not be empty!") } GlobalScope.launch { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = pkgName) + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = pkgName) appLoungePackageManager.setFakeStoreAsInstallerIfNeeded(fusedDownload) - fusedManagerRepository.updateDownloadStatus(fusedDownload, Status.INSTALLED) + appManagerWrapper.updateDownloadStatus(fusedDownload, Status.INSTALLED) } } private fun updateInstallationIssue(pkgName: String) { GlobalScope.launch { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = pkgName) - fusedManagerRepository.installationIssue(fusedDownload) + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = pkgName) + appManagerWrapper.installationIssue(fusedDownload) } } } diff --git a/app/src/main/java/foundation/e/apps/install/receiver/PWAPlayerStatusReceiver.kt b/app/src/main/java/foundation/e/apps/install/receiver/PWAPlayerStatusReceiver.kt index 21aa44c391c07350f20d39177a806c9b2b921988..9b3ed026761cde7a3e3bdcc20145ae6c2223b466 100644 --- a/app/src/main/java/foundation/e/apps/install/receiver/PWAPlayerStatusReceiver.kt +++ b/app/src/main/java/foundation/e/apps/install/receiver/PWAPlayerStatusReceiver.kt @@ -22,7 +22,7 @@ import android.content.Context import android.content.Intent import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.FusedDownloadRepository +import foundation.e.apps.data.install.AppInstallRepository import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -47,20 +47,20 @@ class PWAPlayerStatusReceiver : BroadcastReceiver() { } @Inject - lateinit var fusedDownloadRepository: FusedDownloadRepository + lateinit var appInstallRepository: AppInstallRepository override fun onReceive(context: Context?, intent: Intent?) { GlobalScope.launch { try { intent?.getStringExtra("SHORTCUT_ID")?.let { shortcutId -> - fusedDownloadRepository.getDownloadById(shortcutId)?.let { fusedDownload -> + appInstallRepository.getDownloadById(shortcutId)?.let { fusedDownload -> when (intent.action) { ACTION_PWA_ADDED -> { fusedDownload.status = Status.INSTALLED - fusedDownloadRepository.updateDownload(fusedDownload) + appInstallRepository.updateDownload(fusedDownload) } ACTION_PWA_REMOVED -> { - fusedDownloadRepository.deleteDownload(fusedDownload) + appInstallRepository.deleteDownload(fusedDownload) } } } diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt index ea98da5215be4f52735ca3fd50bf3c468c4983c4..b71e6e6bc029e2371c7a465b1e0913bd67d521b8 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt @@ -22,7 +22,6 @@ import android.content.Context import com.aurora.gplayapi.exceptions.ApiException import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R -import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Status @@ -30,9 +29,9 @@ import foundation.e.apps.data.enums.Type import foundation.e.apps.data.application.ApplicationRepository import foundation.e.apps.data.application.UpdatesDao import foundation.e.apps.data.application.data.Application -import foundation.e.apps.data.fusedDownload.FusedDownloadRepository -import foundation.e.apps.data.fusedDownload.FusedManagerRepository -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppInstallRepository +import foundation.e.apps.data.install.AppManagerWrapper +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.playstore.utils.GplayHttpRequestException import foundation.e.apps.data.preference.DataStoreManager import foundation.e.apps.install.download.DownloadManagerUtils @@ -52,8 +51,8 @@ import javax.inject.Inject class AppInstallProcessor @Inject constructor( @ApplicationContext private val context: Context, - private val fusedDownloadRepository: FusedDownloadRepository, - private val fusedManagerRepository: FusedManagerRepository, + private val appInstallRepository: AppInstallRepository, + private val appManagerWrapper: AppManagerWrapper, private val applicationRepository: ApplicationRepository, private val dataStoreManager: DataStoreManager, private val storageNotificationManager: StorageNotificationManager, @@ -70,7 +69,7 @@ class AppInstallProcessor @Inject constructor( } /** - * creates [FusedDownload] from [Application] and enqueues into WorkManager to run install process. + * creates [AppInstall] from [Application] and enqueues into WorkManager to run install process. * @param application represents the app info which will be installed * @param isAnUpdate indicates the app is requested for update or not * @@ -79,7 +78,7 @@ class AppInstallProcessor @Inject constructor( application: Application, isAnUpdate: Boolean = false ) { - val fusedDownload = FusedDownload( + val appInstall = AppInstall( application._id, application.origin, application.status, @@ -96,83 +95,83 @@ class AppInstallProcessor @Inject constructor( application.originalSize ) - if (fusedDownload.type == Type.PWA) { - fusedDownload.downloadURLList = mutableListOf(application.url) + if (appInstall.type == Type.PWA) { + appInstall.downloadURLList = mutableListOf(application.url) } - enqueueFusedDownload(fusedDownload, isAnUpdate) + enqueueFusedDownload(appInstall, isAnUpdate) } /** - * Enqueues [FusedDownload] into WorkManager to run app install process. Before enqueuing, + * Enqueues [AppInstall] into WorkManager to run app install process. Before enqueuing, * It validates some corner cases - * @param fusedDownload represents the app downloading and installing related info, example- Installing Status, + * @param appInstall represents the app downloading and installing related info, example- Installing Status, * Url of the APK,OBB files are needed to be downloaded and installed etc. * @param isAnUpdate indicates the app is requested for update or not */ suspend fun enqueueFusedDownload( - fusedDownload: FusedDownload, + appInstall: AppInstall, isAnUpdate: Boolean = false ) { try { val authData = dataStoreManager.getAuthData() - if (!fusedDownload.isFree && authData.isAnonymous) { + if (!appInstall.isFree && authData.isAnonymous) { EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.paid_app_anonymous_message)) return } - if (fusedDownload.type != Type.PWA && !updateDownloadUrls(fusedDownload)) return + if (appInstall.type != Type.PWA && !updateDownloadUrls(appInstall)) return - val downloadAdded = fusedManagerRepository.addDownload(fusedDownload) + val downloadAdded = appManagerWrapper.addDownload(appInstall) if (!downloadAdded) { Timber.i("Update adding ABORTED! status: $downloadAdded") return } if (!context.isNetworkAvailable()) { - fusedManagerRepository.installationIssue(fusedDownload) + appManagerWrapper.installationIssue(appInstall) EventBus.invokeEvent(AppEvent.NoInternetEvent(false)) return } - if (StorageComputer.spaceMissing(fusedDownload) > 0) { - Timber.d("Storage is not available for: ${fusedDownload.name} size: ${fusedDownload.appSize}") - storageNotificationManager.showNotEnoughSpaceNotification(fusedDownload) - fusedManagerRepository.installationIssue(fusedDownload) + if (StorageComputer.spaceMissing(appInstall) > 0) { + Timber.d("Storage is not available for: ${appInstall.name} size: ${appInstall.appSize}") + storageNotificationManager.showNotEnoughSpaceNotification(appInstall) + appManagerWrapper.installationIssue(appInstall) EventBus.invokeEvent(AppEvent.ErrorMessageEvent(R.string.not_enough_storage)) return } - fusedManagerRepository.updateAwaiting(fusedDownload) - InstallWorkManager.enqueueWork(fusedDownload, isAnUpdate) + appManagerWrapper.updateAwaiting(appInstall) + InstallWorkManager.enqueueWork(appInstall, isAnUpdate) } catch (e: Exception) { Timber.e( - "Enqueuing App install work is failed for ${fusedDownload.packageName} exception: ${e.localizedMessage}", + "Enqueuing App install work is failed for ${appInstall.packageName} exception: ${e.localizedMessage}", e ) - fusedManagerRepository.installationIssue(fusedDownload) + appManagerWrapper.installationIssue(appInstall) } } // returns TRUE if updating urls is successful, otherwise false. - private suspend fun updateDownloadUrls(fusedDownload: FusedDownload): Boolean { + private suspend fun updateDownloadUrls(appInstall: AppInstall): Boolean { try { - updateFusedDownloadWithAppDownloadLink(fusedDownload) + updateFusedDownloadWithAppDownloadLink(appInstall) } catch (e: ApiException.AppNotPurchased) { - fusedManagerRepository.addFusedDownloadPurchaseNeeded(fusedDownload) - EventBus.invokeEvent(AppEvent.AppPurchaseEvent(fusedDownload)) + appManagerWrapper.addFusedDownloadPurchaseNeeded(appInstall) + EventBus.invokeEvent(AppEvent.AppPurchaseEvent(appInstall)) return false } catch (e: GplayHttpRequestException) { handleUpdateDownloadError( - fusedDownload, - "${fusedDownload.packageName} code: ${e.status} exception: ${e.localizedMessage}", + appInstall, + "${appInstall.packageName} code: ${e.status} exception: ${e.localizedMessage}", e ) return false } catch (e: Exception) { handleUpdateDownloadError( - fusedDownload, - "${fusedDownload.packageName} exception: ${e.localizedMessage}", + appInstall, + "${appInstall.packageName} exception: ${e.localizedMessage}", e ) return false @@ -181,7 +180,7 @@ class AppInstallProcessor @Inject constructor( } private suspend fun handleUpdateDownloadError( - fusedDownload: FusedDownload, + appInstall: AppInstall, message: String, e: Exception ) { @@ -189,17 +188,17 @@ class AppInstallProcessor @Inject constructor( EventBus.invokeEvent( AppEvent.UpdateEvent( ResultSupreme.WorkError( - ResultStatus.UNKNOWN, fusedDownload + ResultStatus.UNKNOWN, appInstall ) ) ) } private suspend fun updateFusedDownloadWithAppDownloadLink( - fusedDownload: FusedDownload + appInstall: AppInstall ) { applicationRepository.updateFusedDownloadWithDownloadingInfo( - fusedDownload.origin, fusedDownload + appInstall.origin, appInstall ) } @@ -209,34 +208,34 @@ class AppInstallProcessor @Inject constructor( isItUpdateWork: Boolean, runInForeground: (suspend (String) -> Unit)? = null ): Result { - var fusedDownload: FusedDownload? = null + var appInstall: AppInstall? = null try { Timber.d("Fused download name $fusedDownloadId") - fusedDownload = fusedDownloadRepository.getDownloadById(fusedDownloadId) - Timber.i(">>> dowork started for Fused download name " + fusedDownload?.name + " " + fusedDownloadId) + appInstall = appInstallRepository.getDownloadById(fusedDownloadId) + Timber.i(">>> dowork started for Fused download name " + appInstall?.name + " " + fusedDownloadId) - fusedDownload?.let { + appInstall?.let { - checkDownloadingState(fusedDownload) + checkDownloadingState(appInstall) this.isItUpdateWork = - isItUpdateWork && fusedManagerRepository.isFusedDownloadInstalled(fusedDownload) + isItUpdateWork && appManagerWrapper.isFusedDownloadInstalled(appInstall) - if (!fusedDownload.isAppInstalling()) { + if (!appInstall.isAppInstalling()) { Timber.d("!!! returned") return@let } - if (!fusedManagerRepository.validateFusedDownload(fusedDownload)) { - fusedManagerRepository.installationIssue(it) + if (!appManagerWrapper.validateFusedDownload(appInstall)) { + appManagerWrapper.installationIssue(it) Timber.d("!!! installationIssue") return@let } - if (areFilesDownloadedButNotInstalled(fusedDownload)) { - Timber.i("===> Downloaded But not installed ${fusedDownload.name}") - fusedManagerRepository.updateDownloadStatus(fusedDownload, Status.INSTALLING) + if (areFilesDownloadedButNotInstalled(appInstall)) { + Timber.i("===> Downloaded But not installed ${appInstall.name}") + appManagerWrapper.updateDownloadStatus(appInstall, Status.INSTALLING) } runInForeground?.invoke(it.name) @@ -245,39 +244,39 @@ class AppInstallProcessor @Inject constructor( } } catch (e: Exception) { Timber.e( - "Install worker is failed for ${fusedDownload?.packageName} exception: ${e.localizedMessage}", + "Install worker is failed for ${appInstall?.packageName} exception: ${e.localizedMessage}", e ) - fusedDownload?.let { - fusedManagerRepository.cancelDownload(fusedDownload) + appInstall?.let { + appManagerWrapper.cancelDownload(appInstall) } } - Timber.i("doWork: RESULT SUCCESS: ${fusedDownload?.name}") + Timber.i("doWork: RESULT SUCCESS: ${appInstall?.name}") return Result.success(ResultStatus.OK) } @OptIn(DelicateCoroutinesApi::class) - private fun checkDownloadingState(fusedDownload: FusedDownload) { - if (fusedDownload.status == Status.DOWNLOADING) { - fusedDownload.downloadIdMap.keys.forEach { downloadId -> + private fun checkDownloadingState(appInstall: AppInstall) { + if (appInstall.status == Status.DOWNLOADING) { + appInstall.downloadIdMap.keys.forEach { downloadId -> downloadManager.updateDownloadStatus(downloadId) } } } - private fun areFilesDownloadedButNotInstalled(fusedDownload: FusedDownload) = - fusedDownload.areFilesDownloaded() && (!fusedManagerRepository.isFusedDownloadInstalled( - fusedDownload - ) || fusedDownload.status == Status.INSTALLING) + private fun areFilesDownloadedButNotInstalled(appInstall: AppInstall) = + appInstall.areFilesDownloaded() && (!appManagerWrapper.isFusedDownloadInstalled( + appInstall + ) || appInstall.status == Status.INSTALLING) private suspend fun checkUpdateWork( - fusedDownload: FusedDownload? + appInstall: AppInstall? ) { if (isItUpdateWork) { - fusedDownload?.let { + appInstall?.let { val packageStatus = - fusedManagerRepository.getFusedDownloadPackageStatus(fusedDownload) + appManagerWrapper.getFusedDownloadPackageStatus(appInstall) if (packageStatus == Status.INSTALLED) { UpdatesDao.addSuccessfullyUpdatedApp(it) @@ -292,7 +291,7 @@ class AppInstallProcessor @Inject constructor( } private suspend fun isUpdateCompleted(): Boolean { - val downloadListWithoutAnyIssue = fusedDownloadRepository.getDownloadList().filter { + val downloadListWithoutAnyIssue = appInstallRepository.getDownloadList().filter { !listOf( Status.INSTALLATION_ISSUE, Status.PURCHASE_NEEDED ).contains(it.status) @@ -316,45 +315,45 @@ class AppInstallProcessor @Inject constructor( ) } - private suspend fun startAppInstallationProcess(fusedDownload: FusedDownload) { - if (fusedDownload.isAwaiting()) { - fusedManagerRepository.downloadApp(fusedDownload) - Timber.i("===> doWork: Download started ${fusedDownload.name} ${fusedDownload.status}") + private suspend fun startAppInstallationProcess(appInstall: AppInstall) { + if (appInstall.isAwaiting()) { + appManagerWrapper.downloadApp(appInstall) + Timber.i("===> doWork: Download started ${appInstall.name} ${appInstall.status}") } - fusedDownloadRepository.getDownloadFlowById(fusedDownload.id).transformWhile { + appInstallRepository.getDownloadFlowById(appInstall.id).transformWhile { emit(it) isInstallRunning(it) }.collect { latestFusedDownload -> - handleFusedDownload(latestFusedDownload, fusedDownload) + handleFusedDownload(latestFusedDownload, appInstall) } } /** - * Takes actions depending on the status of [FusedDownload] + * Takes actions depending on the status of [AppInstall] * - * @param latestFusedDownload comes from Room database when [Status] is updated - * @param fusedDownload is the original object when install process isn't started. It's used when [latestFusedDownload] + * @param latestAppInstall comes from Room database when [Status] is updated + * @param appInstall is the original object when install process isn't started. It's used when [latestAppInstall] * becomes null, After installation is completed. */ private suspend fun handleFusedDownload( - latestFusedDownload: FusedDownload?, - fusedDownload: FusedDownload + latestAppInstall: AppInstall?, + appInstall: AppInstall ) { - if (latestFusedDownload == null) { + if (latestAppInstall == null) { Timber.d("===> download null: finish installation") - finishInstallation(fusedDownload) + finishInstallation(appInstall) return } - handleFusedDownloadStatusCheckingException(latestFusedDownload) + handleFusedDownloadStatusCheckingException(latestAppInstall) } - private fun isInstallRunning(it: FusedDownload?) = + private fun isInstallRunning(it: AppInstall?) = it != null && it.status != Status.INSTALLATION_ISSUE private suspend fun handleFusedDownloadStatusCheckingException( - download: FusedDownload + download: AppInstall ) { try { handleFusedDownloadStatus(download) @@ -362,39 +361,39 @@ class AppInstallProcessor @Inject constructor( val message = "Handling install status is failed for ${download.packageName} exception: ${e.localizedMessage}" Timber.e(message, e) - fusedManagerRepository.installationIssue(download) + appManagerWrapper.installationIssue(download) finishInstallation(download) } } - private suspend fun handleFusedDownloadStatus(fusedDownload: FusedDownload) { - when (fusedDownload.status) { + private suspend fun handleFusedDownloadStatus(appInstall: AppInstall) { + when (appInstall.status) { Status.AWAITING, Status.DOWNLOADING -> { } Status.DOWNLOADED -> { - fusedManagerRepository.updateDownloadStatus(fusedDownload, Status.INSTALLING) + appManagerWrapper.updateDownloadStatus(appInstall, Status.INSTALLING) } Status.INSTALLING -> { - Timber.i("===> doWork: Installing ${fusedDownload.name} ${fusedDownload.status}") + Timber.i("===> doWork: Installing ${appInstall.name} ${appInstall.status}") } Status.INSTALLED, Status.INSTALLATION_ISSUE -> { - Timber.i("===> doWork: Installed/Failed: ${fusedDownload.name} ${fusedDownload.status}") - finishInstallation(fusedDownload) + Timber.i("===> doWork: Installed/Failed: ${appInstall.name} ${appInstall.status}") + finishInstallation(appInstall) } else -> { Timber.wtf( - TAG, "===> ${fusedDownload.name} is in wrong state ${fusedDownload.status}" + TAG, "===> ${appInstall.name} is in wrong state ${appInstall.status}" ) - finishInstallation(fusedDownload) + finishInstallation(appInstall) } } } - private suspend fun finishInstallation(fusedDownload: FusedDownload) { - checkUpdateWork(fusedDownload) + private suspend fun finishInstallation(appInstall: AppInstall) { + checkUpdateWork(appInstall) } } diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/InstallWorkManager.kt b/app/src/main/java/foundation/e/apps/install/workmanager/InstallWorkManager.kt index aa838b785e38861ecb9d4d16332a6e94ab9188c8..37a459be1bcb12000b3eb538de982cdab41fdaa1 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/InstallWorkManager.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/InstallWorkManager.kt @@ -5,23 +5,23 @@ import androidx.work.Data import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import java.lang.Exception object InstallWorkManager { const val INSTALL_WORK_NAME = "APP_LOUNGE_INSTALL_APP" lateinit var context: Application - fun enqueueWork(fusedDownload: FusedDownload, isUpdateWork: Boolean = false) { + fun enqueueWork(appInstall: AppInstall, isUpdateWork: Boolean = false) { WorkManager.getInstance(context).enqueueUniqueWork( INSTALL_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, OneTimeWorkRequestBuilder().setInputData( Data.Builder() - .putString(InstallAppWorker.INPUT_DATA_FUSED_DOWNLOAD, fusedDownload.id) + .putString(InstallAppWorker.INPUT_DATA_FUSED_DOWNLOAD, appInstall.id) .putBoolean(InstallAppWorker.IS_UPDATE_WORK, isUpdateWork) .build() - ).addTag(fusedDownload.id) + ).addTag(appInstall.id) .build() ) } diff --git a/app/src/main/java/foundation/e/apps/receivers/DumpAppInstallStatusReceiver.kt b/app/src/main/java/foundation/e/apps/receivers/DumpAppInstallStatusReceiver.kt index f28ada6a4e24b6758f5be3a548dba0e555a01490..d8b859b4f1e348b66a48047f548f66bf090d7c97 100644 --- a/app/src/main/java/foundation/e/apps/receivers/DumpAppInstallStatusReceiver.kt +++ b/app/src/main/java/foundation/e/apps/receivers/DumpAppInstallStatusReceiver.kt @@ -29,8 +29,8 @@ import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.Constants import foundation.e.apps.data.DownloadManager import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.FusedDownloadRepository -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppInstallRepository +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.utils.NetworkStatusManager import foundation.e.apps.utils.StorageComputer import kotlinx.coroutines.MainScope @@ -43,7 +43,7 @@ import javax.inject.Inject class DumpAppInstallStatusReceiver : BroadcastReceiver() { @Inject - lateinit var fusedDownloadRepository: FusedDownloadRepository + lateinit var appInstallRepository: AppInstallRepository @Inject lateinit var downloadManager: DownloadManager @@ -55,7 +55,7 @@ class DumpAppInstallStatusReceiver : BroadcastReceiver() { MainScope().launch { val gson = Gson() - val appList = fusedDownloadRepository.getDownloadList() + val appList = appInstallRepository.getDownloadList() val appInstallStatusLog = "App install status: ${gson.toJson(appList)}" val deviceStatusLog = getDeviceInfo(context) val downloadStatusLog = getDownloadStatus(appList) @@ -79,7 +79,7 @@ class DumpAppInstallStatusReceiver : BroadcastReceiver() { return null } - private fun getDownloadStatus(appList: List): String { + private fun getDownloadStatus(appList: List): String { var downloadStatusLog = "" appList.forEach { if (listOf(Status.DOWNLOADING, Status.DOWNLOADED).contains(it.status)) { diff --git a/app/src/main/java/foundation/e/apps/ui/AppProgressViewModel.kt b/app/src/main/java/foundation/e/apps/ui/AppProgressViewModel.kt index 28ecaa2bd74171a103959bb2424c8656e07f2c2b..01a5dd5c142e8d9402723b7455e2b300ee05a859 100644 --- a/app/src/main/java/foundation/e/apps/ui/AppProgressViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/AppProgressViewModel.kt @@ -21,7 +21,7 @@ package foundation.e.apps.ui import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.data.application.data.Application -import foundation.e.apps.data.fusedDownload.FusedManagerRepository +import foundation.e.apps.data.install.AppManagerWrapper import foundation.e.apps.install.download.data.DownloadProgress import foundation.e.apps.install.download.data.DownloadProgressLD import javax.inject.Inject @@ -29,7 +29,7 @@ import javax.inject.Inject @HiltViewModel class AppProgressViewModel @Inject constructor( downloadProgressLD: DownloadProgressLD, - private val fusedManagerRepository: FusedManagerRepository + private val appManagerWrapper: AppManagerWrapper ) : ViewModel() { val downloadProgress = downloadProgressLD @@ -38,6 +38,6 @@ class AppProgressViewModel @Inject constructor( application: Application?, progress: DownloadProgress ): Int { - return fusedManagerRepository.calculateProgress(application, progress) + return appManagerWrapper.calculateProgress(application, progress) } } diff --git a/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt b/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt index 9a54ffd78952f18707b411279171fce6a03bfef9..d7604a66af9ff571185d944a03d64443df3d1e12 100644 --- a/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt @@ -39,8 +39,8 @@ import foundation.e.apps.data.ecloud.EcloudRepository import foundation.e.apps.data.enums.User import foundation.e.apps.data.enums.isInitialized import foundation.e.apps.data.enums.isUnFiltered -import foundation.e.apps.data.fusedDownload.FusedManagerRepository -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppManagerWrapper +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.data.preference.getSync import foundation.e.apps.install.pkg.AppLoungePackageManager @@ -54,7 +54,7 @@ import javax.inject.Inject class MainActivityViewModel @Inject constructor( private val appLoungeDataStore: AppLoungeDataStore, private val applicationRepository: ApplicationRepository, - private val fusedManagerRepository: FusedManagerRepository, + private val appManagerWrapper: AppManagerWrapper, private val appLoungePackageManager: AppLoungePackageManager, private val pwaManager: PWAManager, private val ecloudRepository: EcloudRepository, @@ -64,8 +64,8 @@ class MainActivityViewModel @Inject constructor( val tocStatus: LiveData = appLoungeDataStore.tocStatus.asLiveData() - private val _purchaseAppLiveData: MutableLiveData = MutableLiveData() - val purchaseAppLiveData: LiveData = _purchaseAppLiveData + private val _purchaseAppLiveData: MutableLiveData = MutableLiveData() + val purchaseAppLiveData: LiveData = _purchaseAppLiveData val isAppPurchased: MutableLiveData = MutableLiveData() val purchaseDeclined: MutableLiveData = MutableLiveData() lateinit var internetConnection: LiveData @@ -73,7 +73,7 @@ class MainActivityViewModel @Inject constructor( var gPlayAuthData = AuthData("", "") // Downloads - val downloadList = fusedManagerRepository.getDownloadLiveList() + val downloadList = appManagerWrapper.getDownloadLiveList() private val _errorMessage = MutableLiveData() val errorMessage: LiveData = _errorMessage @@ -104,7 +104,7 @@ class MainActivityViewModel @Inject constructor( @RequiresApi(Build.VERSION_CODES.O) fun createNotificationChannels() { - fusedManagerRepository.createNotificationChannels() + appManagerWrapper.createNotificationChannels() } /* @@ -182,8 +182,8 @@ class MainActivityViewModel @Inject constructor( } } - suspend fun updateAwaitingForPurchasedApp(packageName: String): FusedDownload? { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = packageName) + suspend fun updateAwaitingForPurchasedApp(packageName: String): AppInstall? { + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = packageName) gPlayAuthData.let { if (!it.isAnonymous) { appInstallProcessor.enqueueFusedDownload(fusedDownload) @@ -194,15 +194,15 @@ class MainActivityViewModel @Inject constructor( } suspend fun updateUnavailableForPurchaseDeclined(packageName: String) { - val fusedDownload = fusedManagerRepository.getFusedDownload(packageName = packageName) - fusedManagerRepository.updateUnavailable(fusedDownload) + val fusedDownload = appManagerWrapper.getFusedDownload(packageName = packageName) + appManagerWrapper.updateUnavailable(fusedDownload) } fun cancelDownload(app: Application) { viewModelScope.launch { val fusedDownload = - fusedManagerRepository.getFusedDownload(packageName = app.package_name) - fusedManagerRepository.cancelDownload(fusedDownload) + appManagerWrapper.getFusedDownload(packageName = app.package_name) + appManagerWrapper.cancelDownload(fusedDownload) } } @@ -212,10 +212,10 @@ class MainActivityViewModel @Inject constructor( fun updateStatusOfFusedApps( applicationList: List, - fusedDownloadList: List + appInstallList: List ) { applicationList.forEach { - val downloadingItem = fusedDownloadList.find { fusedDownload -> + val downloadingItem = appInstallList.find { fusedDownload -> fusedDownload.origin == it.origin && (fusedDownload.packageName == it.package_name || fusedDownload.id == it._id) } it.status = diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt index 57b2be86f6c3d5ce6790a22581f1e1327c222308..50869d8357fa9a20472af5c4d9ce4d2b4b168acd 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt @@ -31,8 +31,8 @@ import foundation.e.apps.data.application.data.shareUri import foundation.e.apps.data.enums.Origin import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.FusedManagerRepository -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppManagerWrapper +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.exceptions.CleanApkException import foundation.e.apps.data.login.exceptions.GPlayException @@ -53,8 +53,8 @@ import javax.inject.Inject class ApplicationViewModel @Inject constructor( downloadProgressLD: DownloadProgressLD, private val applicationRepository: ApplicationRepository, - private val fusedManagerRepository: FusedManagerRepository, private val playStoreRepository: PlayStoreRepository, + private val appManagerWrapper: AppManagerWrapper, ) : LoadingViewModel() { val application: MutableLiveData> = MutableLiveData() @@ -209,19 +209,19 @@ class ApplicationViewModel @Inject constructor( } fun handleRatingFormat(rating: Double): String { - return fusedManagerRepository.handleRatingFormat(rating) + return appManagerWrapper.handleRatingFormat(rating) } suspend fun calculateProgress(progress: DownloadProgress): Pair { - return fusedManagerRepository.getCalculateProgressWithTotalSize( + return appManagerWrapper.getCalculateProgressWithTotalSize( application.value?.first, progress ) } - fun updateApplicationStatus(downloadList: List) { + fun updateApplicationStatus(downloadList: List) { application.value?.first?.let { app -> - appStatus.value = fusedManagerRepository.getDownloadingItemStatus(app, downloadList) + appStatus.value = appManagerWrapper.getDownloadingItemStatus(app, downloadList) ?: applicationRepository.getFusedAppInstallationStatus(app) } } diff --git a/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt b/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt index 0554904c4e03dd781039287504f177679e98e98e..492b3b6dc0f2d73571e609558aea82d05bcfd24a 100644 --- a/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt @@ -47,7 +47,7 @@ import foundation.e.apps.R import foundation.e.apps.data.enums.Status import foundation.e.apps.data.application.ApplicationInstaller import foundation.e.apps.data.application.data.Application -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.exceptions.GPlayLoginException import foundation.e.apps.databinding.FragmentSearchBinding @@ -328,13 +328,13 @@ class SearchFragment : } private fun refreshUI( - fusedDownloadList: List, + appInstallList: List, applicationListRVAdapter: ApplicationListRVAdapter ) { val searchList = searchViewModel.searchResult.value?.data?.first?.toMutableList() ?: emptyList() - mainActivityViewModel.updateStatusOfFusedApps(searchList, fusedDownloadList) + mainActivityViewModel.updateStatusOfFusedApps(searchList, appInstallList) updateSearchResult(applicationListRVAdapter, searchList) } diff --git a/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt b/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt index 13d9c372067530c9161053ef33c80b363cbdd2b8..fc68ab0b2bd4936dec0f16ae028026f1e04d0f12 100644 --- a/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt @@ -38,7 +38,7 @@ import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Status import foundation.e.apps.data.application.ApplicationInstaller import foundation.e.apps.data.application.data.Application -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.data.login.exceptions.GPlayLoginException @@ -202,11 +202,11 @@ class UpdatesFragment : TimeoutFragment(R.layout.fragment_updates), ApplicationI return } - if (event.otherPayload is FusedDownload) { + if (event.otherPayload is AppInstall) { requireContext().toast( getString( R.string.message_update_failure_single_app, - (event.otherPayload as FusedDownload).name + (event.otherPayload as AppInstall).name ) ) } diff --git a/app/src/main/java/foundation/e/apps/utils/StorageComputer.kt b/app/src/main/java/foundation/e/apps/utils/StorageComputer.kt index e7be20dba4d87ca434c1a64567761670b03669cf..e3ca3c403233413c37b6f1685170859edc30ab98 100644 --- a/app/src/main/java/foundation/e/apps/utils/StorageComputer.kt +++ b/app/src/main/java/foundation/e/apps/utils/StorageComputer.kt @@ -19,17 +19,17 @@ package foundation.e.apps.utils import android.os.Environment import android.os.StatFs -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall import java.text.CharacterIterator import java.text.StringCharacterIterator object StorageComputer { - fun spaceMissing(fusedDownload: FusedDownload): Long { - return getRequiredSpace(fusedDownload) - calculateAvailableDiskSpace() + fun spaceMissing(appInstall: AppInstall): Long { + return getRequiredSpace(appInstall) - calculateAvailableDiskSpace() } - private fun getRequiredSpace(fusedDownload: FusedDownload) = - fusedDownload.appSize + (500 * (1000 * 1000)) + private fun getRequiredSpace(appInstall: AppInstall) = + appInstall.appSize + (500 * (1000 * 1000)) fun calculateAvailableDiskSpace(): Long { val path = Environment.getDataDirectory().absolutePath diff --git a/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt b/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt index f7fbf663aa65ce9bef55f94a50169c90eff09064..30494abb82edf3c55f52cc2bc792313eee0ad1fd 100644 --- a/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt +++ b/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt @@ -22,7 +22,7 @@ package foundation.e.apps.utils.eventBus import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.enums.ResultStatus -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.models.AppInstall sealed class AppEvent(val data: Any) { class SignatureMissMatchError(packageName: String) : AppEvent(packageName) @@ -30,7 +30,7 @@ sealed class AppEvent(val data: Any) { class InvalidAuthEvent(authName: String) : AppEvent(authName) class ErrorMessageEvent(stringResourceId: Int) : AppEvent(stringResourceId) - class AppPurchaseEvent(fusedDownload: FusedDownload) : AppEvent(fusedDownload) + class AppPurchaseEvent(appInstall: AppInstall) : AppEvent(appInstall) class NoInternetEvent(isInternetAvailable: Boolean) : AppEvent(isInternetAvailable) class TooManyRequests : AppEvent(Unit) } diff --git a/app/src/test/java/foundation/e/apps/fusedManager/FusedManagerRepositoryTest.kt b/app/src/test/java/foundation/e/apps/fusedManager/AppManagerWrapperTest.kt similarity index 71% rename from app/src/test/java/foundation/e/apps/fusedManager/FusedManagerRepositoryTest.kt rename to app/src/test/java/foundation/e/apps/fusedManager/AppManagerWrapperTest.kt index 5d47945b1d14ee39d4d34352317bcc1ca65133d8..4fe3108f597214c3fd28921759c85640accd611e 100644 --- a/app/src/test/java/foundation/e/apps/fusedManager/FusedManagerRepositoryTest.kt +++ b/app/src/test/java/foundation/e/apps/fusedManager/AppManagerWrapperTest.kt @@ -22,10 +22,10 @@ import android.app.Application import androidx.arch.core.executor.testing.InstantTaskExecutorRule import foundation.e.apps.data.enums.Status import foundation.e.apps.data.fdroid.FdroidRepository -import foundation.e.apps.data.fusedDownload.FusedManagerRepository -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppManagerWrapper +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.install.workmanager.InstallWorkManager -import foundation.e.apps.installProcessor.FakeFusedDownloadDAO +import foundation.e.apps.installProcessor.FakeAppInstallDAO import foundation.e.apps.util.MainCoroutineRule import io.mockk.every import io.mockk.mockkObject @@ -41,7 +41,7 @@ import org.mockito.Mock import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) -class FusedManagerRepositoryTest { +class AppManagerWrapperTest { @Rule @JvmField val instantExecutorRule = InstantTaskExecutorRule() @@ -51,8 +51,8 @@ class FusedManagerRepositoryTest { @get:Rule var mainCoroutineRule = MainCoroutineRule() - private lateinit var fusedDownloadDAO: FakeFusedDownloadDAO - private lateinit var fakeFusedManager: FakeFusedManager + private lateinit var appInstallDAO: FakeAppInstallDAO + private lateinit var fakeAppManager: FakeAppManager @Mock private lateinit var application: Application @@ -60,27 +60,27 @@ class FusedManagerRepositoryTest { @Mock private lateinit var fdroidRepository: FdroidRepository - private lateinit var fusedManagerRepository: FusedManagerRepository + private lateinit var appManagerWrapper: AppManagerWrapper @Before fun setup() { MockitoAnnotations.openMocks(this) InstallWorkManager.context = application - fusedDownloadDAO = FakeFusedDownloadDAO() - fakeFusedManager = FakeFusedManager(fusedDownloadDAO) - fusedManagerRepository = FusedManagerRepository(fakeFusedManager, fdroidRepository) + appInstallDAO = FakeAppInstallDAO() + fakeAppManager = FakeAppManager(appInstallDAO) + appManagerWrapper = AppManagerWrapper(fakeAppManager, fdroidRepository) } @Test fun addDownload() = runTest { val fusedDownload = initTest() - val isSuccessful = fusedManagerRepository.addDownload(fusedDownload) + val isSuccessful = appManagerWrapper.addDownload(fusedDownload) assertTrue("addDownload", isSuccessful) - assertEquals("addDownload", 1, fusedDownloadDAO.getDownloadList().size) + assertEquals("addDownload", 1, appInstallDAO.getDownloadList().size) } - private fun initTest(hasAnyExistingWork: Boolean = false): FusedDownload { + private fun initTest(hasAnyExistingWork: Boolean = false): AppInstall { mockkObject(InstallWorkManager) every { InstallWorkManager.checkWorkIsAlreadyAvailable(any()) } returns hasAnyExistingWork return createFusedDownload() @@ -89,9 +89,9 @@ class FusedManagerRepositoryTest { @Test fun `addDownload when work and FusedDownload Both are available`() = runTest { val fusedDownload = initTest(true) - fusedDownloadDAO.fusedDownloadList.add(fusedDownload) + appInstallDAO.appInstallList.add(fusedDownload) - val isSuccessful = fusedManagerRepository.addDownload(fusedDownload) + val isSuccessful = appManagerWrapper.addDownload(fusedDownload) assertFalse("addDownload", isSuccessful) } @@ -99,16 +99,16 @@ class FusedManagerRepositoryTest { fun `addDownload when only work exists`() = runTest { val fusedDownload = initTest(true) - val isSuccessful = fusedManagerRepository.addDownload(fusedDownload) + val isSuccessful = appManagerWrapper.addDownload(fusedDownload) assertTrue("addDownload", isSuccessful) } @Test fun `addDownload when on FusedDownload exists`() = runTest { val fusedDownload = initTest() - fusedDownloadDAO.addDownload(fusedDownload) + appInstallDAO.addDownload(fusedDownload) - val isSuccessful = fusedManagerRepository.addDownload(fusedDownload) + val isSuccessful = appManagerWrapper.addDownload(fusedDownload) assertFalse("addDownload", isSuccessful) } @@ -116,16 +116,16 @@ class FusedManagerRepositoryTest { fun `addDownload when fusedDownload already exists And has installation issue`() = runTest { val fusedDownload = initTest() fusedDownload.status = Status.INSTALLATION_ISSUE - fusedDownloadDAO.addDownload(fusedDownload) + appInstallDAO.addDownload(fusedDownload) - val isSuccessful = fusedManagerRepository.addDownload(fusedDownload) + val isSuccessful = appManagerWrapper.addDownload(fusedDownload) assertTrue("addDownload", isSuccessful) } private fun createFusedDownload( packageName: String? = null, downloadUrlList: MutableList? = null - ) = FusedDownload( + ) = AppInstall( id = "121", status = Status.AWAITING, downloadURLList = downloadUrlList ?: mutableListOf("apk1", "apk2"), diff --git a/app/src/test/java/foundation/e/apps/fusedManager/FakeFusedManager.kt b/app/src/test/java/foundation/e/apps/fusedManager/FakeAppManager.kt similarity index 50% rename from app/src/test/java/foundation/e/apps/fusedManager/FakeFusedManager.kt rename to app/src/test/java/foundation/e/apps/fusedManager/FakeAppManager.kt index b77ceadd89ef91cdaf3c5ed8fc1cca54a81af99b..f8f1c97d97ff984fca242d7092c98643c3cf30d4 100644 --- a/app/src/test/java/foundation/e/apps/fusedManager/FakeFusedManager.kt +++ b/app/src/test/java/foundation/e/apps/fusedManager/FakeAppManager.kt @@ -20,50 +20,50 @@ package foundation.e.apps.fusedManager import androidx.lifecycle.LiveData import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.FusedDownloadDAO -import foundation.e.apps.data.fusedDownload.IFusedManager -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppInstallDAO +import foundation.e.apps.data.install.AppManager +import foundation.e.apps.data.install.models.AppInstall import java.io.File -class FakeFusedManager(private val fusedDownloadDAO: FusedDownloadDAO) : IFusedManager { +class FakeAppManager(private val appInstallDAO: AppInstallDAO) : AppManager { override fun createNotificationChannels() { TODO("Not yet implemented") } - override suspend fun addDownload(fusedDownload: FusedDownload) { - fusedDownload.status = Status.QUEUED - fusedDownloadDAO.addDownload(fusedDownload) + override suspend fun addDownload(appInstall: AppInstall) { + appInstall.status = Status.QUEUED + appInstallDAO.addDownload(appInstall) } - override suspend fun getDownloadById(fusedDownload: FusedDownload): FusedDownload? { - return fusedDownloadDAO.getDownloadById(fusedDownload.id) + override suspend fun getDownloadById(appInstall: AppInstall): AppInstall? { + return appInstallDAO.getDownloadById(appInstall.id) } - override suspend fun getDownloadList(): List { + override suspend fun getDownloadList(): List { TODO("Not yet implemented") } - override fun getDownloadLiveList(): LiveData> { + override fun getDownloadLiveList(): LiveData> { TODO("Not yet implemented") } - override suspend fun updateDownloadStatus(fusedDownload: FusedDownload, status: Status) { + override suspend fun updateDownloadStatus(appInstall: AppInstall, status: Status) { TODO("Not yet implemented") } - override suspend fun downloadApp(fusedDownload: FusedDownload) { + override suspend fun downloadApp(appInstall: AppInstall) { TODO("Not yet implemented") } - override suspend fun installApp(fusedDownload: FusedDownload) { + override suspend fun installApp(appInstall: AppInstall) { TODO("Not yet implemented") } - override suspend fun cancelDownload(fusedDownload: FusedDownload) { + override suspend fun cancelDownload(appInstall: AppInstall) { TODO("Not yet implemented") } - override suspend fun getFusedDownload(downloadId: Long, packageName: String): FusedDownload { + override suspend fun getFusedDownload(downloadId: Long, packageName: String): AppInstall { TODO("Not yet implemented") } @@ -71,12 +71,12 @@ class FakeFusedManager(private val fusedDownloadDAO: FusedDownloadDAO) : IFusedM TODO("Not yet implemented") } - override suspend fun downloadNativeApp(fusedDownload: FusedDownload) { + override suspend fun downloadNativeApp(appInstall: AppInstall) { TODO("Not yet implemented") } override fun getGplayInstallationPackagePath( - fusedDownload: FusedDownload, + appInstall: AppInstall, it: String, parentPath: String, count: Int @@ -84,43 +84,43 @@ class FakeFusedManager(private val fusedDownloadDAO: FusedDownloadDAO) : IFusedM TODO("Not yet implemented") } - override fun createObbFileForDownload(fusedDownload: FusedDownload, url: String): File { + override fun createObbFileForDownload(appInstall: AppInstall, url: String): File { TODO("Not yet implemented") } - override fun moveOBBFilesToOBBDirectory(fusedDownload: FusedDownload) { + override fun moveOBBFilesToOBBDirectory(appInstall: AppInstall) { TODO("Not yet implemented") } - override fun getBaseApkPath(fusedDownload: FusedDownload): String { - return "root/data/apps/${fusedDownload.packageName}/${fusedDownload.packageName}_1.apk" + override fun getBaseApkPath(appInstall: AppInstall): String { + return "root/data/apps/${appInstall.packageName}/${appInstall.packageName}_1.apk" } - override suspend fun installationIssue(fusedDownload: FusedDownload) { + override suspend fun installationIssue(appInstall: AppInstall) { TODO("Not yet implemented") } - override suspend fun updateAwaiting(fusedDownload: FusedDownload) { + override suspend fun updateAwaiting(appInstall: AppInstall) { TODO("Not yet implemented") } - override suspend fun updateUnavailable(fusedDownload: FusedDownload) { + override suspend fun updateUnavailable(appInstall: AppInstall) { TODO("Not yet implemented") } - override suspend fun updateFusedDownload(fusedDownload: FusedDownload) { + override suspend fun updateAppInstall(appInstall: AppInstall) { TODO("Not yet implemented") } - override suspend fun insertFusedDownloadPurchaseNeeded(fusedDownload: FusedDownload) { + override suspend fun insertAppInstallPurchaseNeeded(appInstall: AppInstall) { TODO("Not yet implemented") } - override fun isFusedDownloadInstalled(fusedDownload: FusedDownload): Boolean { + override fun isAppInstalled(appInstall: AppInstall): Boolean { TODO("Not yet implemented") } - override fun getFusedDownloadInstallationStatus(fusedApp: FusedDownload): Status { + override fun getInstallationStatus(appInstall: AppInstall): Status { TODO("Not yet implemented") } } diff --git a/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt b/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt index 3bff045e9bd8d904c2511fb4d5ff60e0d22cd43d..6c1a4197488e7367b49a462bfc78071447797b23 100644 --- a/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt +++ b/app/src/test/java/foundation/e/apps/installProcessor/AppInstallProcessorTest.kt @@ -24,9 +24,9 @@ import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.enums.Status import foundation.e.apps.data.fdroid.FdroidRepository import foundation.e.apps.data.application.ApplicationRepository -import foundation.e.apps.data.fusedDownload.FusedDownloadRepository -import foundation.e.apps.data.fusedDownload.IFusedManager -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppInstallRepository +import foundation.e.apps.data.install.AppManager +import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.preference.DataStoreManager import foundation.e.apps.install.notification.StorageNotificationManager import foundation.e.apps.install.workmanager.AppInstallProcessor @@ -54,12 +54,12 @@ class AppInstallProcessorTest { @get:Rule var mainCoroutineRule = MainCoroutineRule() - private lateinit var fakeFusedDownloadDAO: FakeFusedDownloadDAO - private lateinit var fusedDownloadRepository: FusedDownloadRepository - private lateinit var fakeFusedManagerRepository: FakeFusedManagerRepository + private lateinit var fakeFusedDownloadDAO: FakeAppInstallDAO + private lateinit var appInstallRepository: AppInstallRepository + private lateinit var fakeFusedManagerRepository: FakeAppManagerWrapper @Mock - private lateinit var fakeFusedManager: IFusedManager + private lateinit var fakeFusedManager: AppManager @Mock private lateinit var fakeFdroidRepository: FdroidRepository @@ -81,14 +81,14 @@ class AppInstallProcessorTest { @Before fun setup() { MockitoAnnotations.openMocks(this) - fakeFusedDownloadDAO = FakeFusedDownloadDAO() - fusedDownloadRepository = FusedDownloadRepository(fakeFusedDownloadDAO) + fakeFusedDownloadDAO = FakeAppInstallDAO() + appInstallRepository = AppInstallRepository(fakeFusedDownloadDAO) fakeFusedManagerRepository = - FakeFusedManagerRepository(fakeFusedDownloadDAO, fakeFusedManager, fakeFdroidRepository) + FakeAppManagerWrapper(fakeFusedDownloadDAO, fakeFusedManager, fakeFdroidRepository) appInstallProcessor = AppInstallProcessor( context, - fusedDownloadRepository, + appInstallRepository, fakeFusedManagerRepository, applicationRepository, dataStoreManager, @@ -107,7 +107,7 @@ class AppInstallProcessorTest { private suspend fun initTest( packageName: String? = null, downloadUrlList: MutableList? = null - ): FusedDownload { + ): AppInstall { val fusedDownload = createFusedDownload(packageName, downloadUrlList) fakeFusedDownloadDAO.addDownload(fusedDownload) Mockito.`when`(dataStoreManager.getAuthData()).thenReturn(AuthData("", "")) @@ -176,15 +176,15 @@ class AppInstallProcessorTest { assertEquals("processInstall", Status.INSTALLATION_ISSUE, finalFusedDownload?.status) } - private suspend fun runProcessInstall(fusedDownload: FusedDownload): FusedDownload? { - appInstallProcessor.processInstall(fusedDownload.id, false) - return fakeFusedDownloadDAO.getDownloadById(fusedDownload.id) + private suspend fun runProcessInstall(appInstall: AppInstall): AppInstall? { + appInstallProcessor.processInstall(appInstall.id, false) + return fakeFusedDownloadDAO.getDownloadById(appInstall.id) } private fun createFusedDownload( packageName: String? = null, downloadUrlList: MutableList? = null - ) = FusedDownload( + ) = AppInstall( id = "121", status = Status.AWAITING, downloadURLList = downloadUrlList ?: mutableListOf("apk1", "apk2"), diff --git a/app/src/test/java/foundation/e/apps/installProcessor/FakeFusedDownloadDAO.kt b/app/src/test/java/foundation/e/apps/installProcessor/FakeAppInstallDAO.kt similarity index 54% rename from app/src/test/java/foundation/e/apps/installProcessor/FakeFusedDownloadDAO.kt rename to app/src/test/java/foundation/e/apps/installProcessor/FakeAppInstallDAO.kt index dbec4d02ef7c8beb4008961ad8f804fa43e43240..a592e2688ae7a53073735417d1a25871d2c99e67 100644 --- a/app/src/test/java/foundation/e/apps/installProcessor/FakeFusedDownloadDAO.kt +++ b/app/src/test/java/foundation/e/apps/installProcessor/FakeAppInstallDAO.kt @@ -21,33 +21,33 @@ package foundation.e.apps.installProcessor import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fusedDownload.FusedDownloadDAO -import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.install.AppInstallDAO +import foundation.e.apps.data.install.models.AppInstall import kotlinx.coroutines.flow.flow -class FakeFusedDownloadDAO : FusedDownloadDAO { - val fusedDownloadList = mutableListOf() +class FakeAppInstallDAO : AppInstallDAO { + val appInstallList = mutableListOf() - override suspend fun addDownload(fusedDownload: FusedDownload) { - fusedDownloadList.add(fusedDownload) + override suspend fun addDownload(appInstall: AppInstall) { + appInstallList.add(appInstall) } - override fun getDownloadLiveList(): LiveData> { + override fun getDownloadLiveList(): LiveData> { TODO("Not yet implemented") } - override suspend fun getDownloadList(): List { - return fusedDownloadList + override suspend fun getDownloadList(): List { + return appInstallList } - override suspend fun getDownloadById(id: String): FusedDownload? { - return fusedDownloadList.find { it.id == id } + override suspend fun getDownloadById(id: String): AppInstall? { + return appInstallList.find { it.id == id } } - override fun getDownloadFlowById(id: String): LiveData { + override fun getDownloadFlowById(id: String): LiveData { return flow { while (true) { - val fusedDownload = fusedDownloadList.find { it.id == id } + val fusedDownload = appInstallList.find { it.id == id } emit(fusedDownload) if (fusedDownload == null || fusedDownload.status == Status.INSTALLATION_ISSUE) { break @@ -56,11 +56,11 @@ class FakeFusedDownloadDAO : FusedDownloadDAO { }.asLiveData() } - override suspend fun updateDownload(fusedDownload: FusedDownload) { - fusedDownloadList.replaceAll { if (it.id == fusedDownload.id) fusedDownload else it } + override suspend fun updateDownload(appInstall: AppInstall) { + appInstallList.replaceAll { if (it.id == appInstall.id) appInstall else it } } - override suspend fun deleteDownload(fusedDownload: FusedDownload) { - fusedDownloadList.remove(fusedDownload) + override suspend fun deleteDownload(appInstall: AppInstall) { + appInstallList.remove(appInstall) } } diff --git a/app/src/test/java/foundation/e/apps/installProcessor/FakeAppManagerWrapper.kt b/app/src/test/java/foundation/e/apps/installProcessor/FakeAppManagerWrapper.kt new file mode 100644 index 0000000000000000000000000000000000000000..b392cca60e417579a476de78bdca5b5014a3fffb --- /dev/null +++ b/app/src/test/java/foundation/e/apps/installProcessor/FakeAppManagerWrapper.kt @@ -0,0 +1,109 @@ +/* + * Copyright MURENA SAS 2023 + * Apps Quickly and easily install Android apps onto your device! + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.installProcessor + +import foundation.e.apps.data.enums.Status +import foundation.e.apps.data.fdroid.FdroidRepository +import foundation.e.apps.data.install.AppManagerWrapper +import foundation.e.apps.data.install.AppManager +import foundation.e.apps.data.install.models.AppInstall +import kotlinx.coroutines.delay + +class FakeAppManagerWrapper( + private val fusedDownloadDAO: FakeAppInstallDAO, + fusedManager: AppManager, + fdroidRepository: FdroidRepository, +) : AppManagerWrapper(fusedManager, fdroidRepository) { + var isAppInstalled = false + var installationStatus = Status.INSTALLED + var willDownloadFail = false + var willInstallFail = false + var forceCrash = false + + override suspend fun downloadApp(appInstall: AppInstall) { + if (forceCrash) { + System.out.println("Throwing test exception") + throw Exception("test exception!") + } + + appInstall.status = Status.DOWNLOADING + appInstall.downloadIdMap = mutableMapOf(Pair(341, false), Pair(342, false)) + fusedDownloadDAO.updateDownload(appInstall) + delay(5000) + + if (willDownloadFail) { + appInstall.downloadIdMap.clear() + appInstall.downloadIdMap = mutableMapOf(Pair(-1, false), Pair(-1, false)) + appInstall.status = Status.INSTALLATION_ISSUE + fusedDownloadDAO.updateDownload(appInstall) + return + } + + appInstall.downloadIdMap.replaceAll { _, _ -> true } + appInstall.status = Status.DOWNLOADED + fusedDownloadDAO.updateDownload(appInstall) + updateDownloadStatus(appInstall, Status.INSTALLING) + } + + override suspend fun updateDownloadStatus(appInstall: AppInstall, status: Status) { + when (status) { + Status.INSTALLING -> { + handleStatusInstalling(appInstall) + } + Status.INSTALLED -> { + fusedDownloadDAO.deleteDownload(appInstall) + } + else -> { + appInstall.status = status + fusedDownloadDAO.updateDownload(appInstall) + } + } + } + + private suspend fun handleStatusInstalling( + appInstall: AppInstall + ) { + appInstall.status = Status.INSTALLING + fusedDownloadDAO.updateDownload(appInstall) + delay(5000) + + if (willInstallFail) { + updateDownloadStatus(appInstall, Status.INSTALLATION_ISSUE) + } else { + updateDownloadStatus(appInstall, Status.INSTALLED) + } + } + + override suspend fun installationIssue(appInstall: AppInstall) { + appInstall.status = Status.INSTALLATION_ISSUE + fusedDownloadDAO.updateDownload(appInstall) + } + + override fun isFusedDownloadInstalled(appInstall: AppInstall): Boolean { + return isAppInstalled + } + + override fun getFusedDownloadPackageStatus(appInstall: AppInstall): Status { + return installationStatus + } + + override suspend fun cancelDownload(appInstall: AppInstall) { + fusedDownloadDAO.deleteDownload(appInstall) + } +} diff --git a/app/src/test/java/foundation/e/apps/installProcessor/FakeFusedManagerRepository.kt b/app/src/test/java/foundation/e/apps/installProcessor/FakeFusedManagerRepository.kt deleted file mode 100644 index 9b39077a2319b34ff5f9c7a686b54cec078aa5ba..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/apps/installProcessor/FakeFusedManagerRepository.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright MURENA SAS 2023 - * Apps Quickly and easily install Android apps onto your device! - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package foundation.e.apps.installProcessor - -import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.fdroid.FdroidRepository -import foundation.e.apps.data.fusedDownload.FusedManagerRepository -import foundation.e.apps.data.fusedDownload.IFusedManager -import foundation.e.apps.data.fusedDownload.models.FusedDownload -import kotlinx.coroutines.delay - -class FakeFusedManagerRepository( - private val fusedDownloadDAO: FakeFusedDownloadDAO, - fusedManager: IFusedManager, - fdroidRepository: FdroidRepository, -) : FusedManagerRepository(fusedManager, fdroidRepository) { - var isAppInstalled = false - var installationStatus = Status.INSTALLED - var willDownloadFail = false - var willInstallFail = false - var forceCrash = false - - override suspend fun downloadApp(fusedDownload: FusedDownload) { - if (forceCrash) { - System.out.println("Throwing test exception") - throw Exception("test exception!") - } - - fusedDownload.status = Status.DOWNLOADING - fusedDownload.downloadIdMap = mutableMapOf(Pair(341, false), Pair(342, false)) - fusedDownloadDAO.updateDownload(fusedDownload) - delay(5000) - - if (willDownloadFail) { - fusedDownload.downloadIdMap.clear() - fusedDownload.downloadIdMap = mutableMapOf(Pair(-1, false), Pair(-1, false)) - fusedDownload.status = Status.INSTALLATION_ISSUE - fusedDownloadDAO.updateDownload(fusedDownload) - return - } - - fusedDownload.downloadIdMap.replaceAll { _, _ -> true } - fusedDownload.status = Status.DOWNLOADED - fusedDownloadDAO.updateDownload(fusedDownload) - updateDownloadStatus(fusedDownload, Status.INSTALLING) - } - - override suspend fun updateDownloadStatus(fusedDownload: FusedDownload, status: Status) { - when (status) { - Status.INSTALLING -> { - handleStatusInstalling(fusedDownload) - } - Status.INSTALLED -> { - fusedDownloadDAO.deleteDownload(fusedDownload) - } - else -> { - fusedDownload.status = status - fusedDownloadDAO.updateDownload(fusedDownload) - } - } - } - - private suspend fun handleStatusInstalling( - fusedDownload: FusedDownload - ) { - fusedDownload.status = Status.INSTALLING - fusedDownloadDAO.updateDownload(fusedDownload) - delay(5000) - - if (willInstallFail) { - updateDownloadStatus(fusedDownload, Status.INSTALLATION_ISSUE) - } else { - updateDownloadStatus(fusedDownload, Status.INSTALLED) - } - } - - override suspend fun installationIssue(fusedDownload: FusedDownload) { - fusedDownload.status = Status.INSTALLATION_ISSUE - fusedDownloadDAO.updateDownload(fusedDownload) - } - - override fun isFusedDownloadInstalled(fusedDownload: FusedDownload): Boolean { - return isAppInstalled - } - - override fun getFusedDownloadPackageStatus(fusedDownload: FusedDownload): Status { - return installationStatus - } - - override suspend fun cancelDownload(fusedDownload: FusedDownload) { - fusedDownloadDAO.deleteDownload(fusedDownload) - } -}