From ff69759634ac97e886a46559d8950906fe2e56df Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Tue, 12 May 2026 20:51:21 +0530 Subject: [PATCH] microg: improve installer state detection --- .../compose/ui/details/AppDetailsScreen.kt | 2 +- .../store/compose/ui/details/MicroGScreen.kt | 10 +-- .../viewmodel/onboarding/MicroGViewModel.kt | 69 +++++++++++++++---- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt index 9dc8d23af..a4b9342fb 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt @@ -620,7 +620,7 @@ private fun ScreenContentApp( is ExtraScreen.MicroG -> MicroGScreen( packageName = app.packageName, onNavigateUp = ::onNavigateBack, - onIgnore = { onInstall(ignoreMicroG = it) } + onProceed = { onInstall(ignoreMicroG = true) } ) is Screen.DevProfile -> DevProfileScreen( diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/MicroGScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/MicroGScreen.kt index 2b044cd26..145c6cda9 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/details/MicroGScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/details/MicroGScreen.kt @@ -56,14 +56,14 @@ import com.aurora.store.viewmodel.onboarding.MicroGViewModel fun MicroGScreen( packageName: String, onNavigateUp: () -> Unit, - onIgnore: (Boolean) -> Unit, + onProceed: () -> Unit, appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), viewModel: MicroGViewModel = hiltViewModel(), windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfoV2() ) { val app by appDetailsViewModel.app.collectAsStateWithLifecycle() val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app!!.displayName + windowAdaptiveInfo.isWindowCompact -> app?.displayName else -> stringResource(R.string.onboarding_title_gsf) } @@ -73,7 +73,7 @@ fun MicroGScreen( onNavigateUp = onNavigateUp, onInstall = { viewModel.downloadMicroG() }, onRetry = { viewModel.retryDownload() }, - onIgnore = onIgnore + onProceed = onProceed ) } @@ -84,7 +84,7 @@ private fun ScreenContent( onNavigateUp: () -> Unit = {}, onInstall: () -> Unit = {}, onRetry: () -> Unit = {}, - onIgnore: (Boolean) -> Unit = {}, + onProceed: () -> Unit = {}, windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfoV2() ) { val context = LocalContext.current @@ -123,7 +123,7 @@ private fun ScreenContent( Button( modifier = Modifier.weight(1F), - onClick = { onIgnore(uiState.isInstalled) }, + onClick = onProceed, enabled = !uiState.isInProgress ) { Text( diff --git a/app/src/main/java/com/aurora/store/viewmodel/onboarding/MicroGViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/onboarding/MicroGViewModel.kt index c2c697960..fd4eb2ea8 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/onboarding/MicroGViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/onboarding/MicroGViewModel.kt @@ -113,20 +113,33 @@ class MicroGViewModel @Inject constructor( private val bundle = listOf(microGServiceApk, microGCompanionApk) init { - AuroraApp.events.installerEvent.onEach { - if (it is InstallerEvent.Installed) refresh() + AuroraApp.events.installerEvent.onEach { event -> + when (event) { + is InstallerEvent.Installed -> refresh() + is InstallerEvent.Uninstalled -> handleUninstall(event.packageName) + else -> {} + } }.launchIn(AuroraApp.scope) - combine( - downloadHelper.downloadsList, - networkProvider.status.onStart { emit(NetworkStatus.AVAILABLE) } - ) { downloads, network -> - val byPackage = downloads.associateBy { it.packageName } - MicroGUIState( - items = bundle.map { apk -> buildItem(apk, byPackage[apk.packageName]) }, - isOnline = network == NetworkStatus.AVAILABLE - ) - }.onEach { uiState = it }.launchIn(viewModelScope) + viewModelScope.launch { + bundle.forEach { apk -> + val download = downloadHelper.getDownload(apk.packageName) + if (download?.status == DownloadStatus.COMPLETED && !isBundleApkInstalled(apk)) { + downloadHelper.removeDownload(apk.packageName) + } + } + + combine( + downloadHelper.downloadsList, + networkProvider.status.onStart { emit(NetworkStatus.AVAILABLE) } + ) { downloads, network -> + val byPackage = downloads.associateBy { it.packageName } + MicroGUIState( + items = bundle.map { apk -> buildItem(apk, byPackage[apk.packageName]) }, + isOnline = network == NetworkStatus.AVAILABLE + ) + }.onEach { uiState = it }.launchIn(viewModelScope) + } } fun downloadMicroG() { @@ -147,18 +160,44 @@ class MicroGViewModel @Inject constructor( } private suspend fun enqueueIfNeeded(apk: ExternalApk) { - if (apk.isInstalled(context)) { + if (isBundleApkInstalled(apk)) { AuroraApp.events.send(InstallerEvent.Installed(apk.packageName)) } else { downloadHelper.enqueueStandalone(apk) } } + // Validate against the microG-specific signature/version checks rather than mere package + // presence — a stock Play Store or older Companion would otherwise be reported as installed. + private fun isBundleApkInstalled(apk: ExternalApk): Boolean = when (apk.packageName) { + PACKAGE_NAME_GMS -> PackageUtil.hasSupportedMicroGVariant(context) + PACKAGE_NAME_PLAY_STORE -> PackageUtil.hasMicroGCompanion(context) + else -> apk.isInstalled(context) + } + + private fun handleUninstall(packageName: String) { + val apk = bundle.find { it.packageName == packageName } ?: return + viewModelScope.launch { + downloadHelper.removeDownload(packageName) + uiState = uiState.copy( + items = uiState.items.map { item -> + if (item.packageName == apk.packageName) { + item.copy(status = InstallStatus.PENDING, progress = 0) + } else { + item + } + } + ) + } + } + private fun refresh() { uiState = uiState.copy( items = uiState.items.map { item -> + val apk = bundle.find { it.packageName == item.packageName } if (item.status != InstallStatus.INSTALLED && - PackageUtil.isInstalled(context, item.packageName) + apk != null && + isBundleApkInstalled(apk) ) { item.copy(status = InstallStatus.INSTALLED) } else { @@ -170,7 +209,7 @@ class MicroGViewModel @Inject constructor( private fun buildItem(apk: ExternalApk, download: Download?): ExternalItem { val state = when { - apk.isInstalled(context) -> InstallStatus.INSTALLED + isBundleApkInstalled(apk) -> InstallStatus.INSTALLED download == null -> InstallStatus.PENDING download.status == DownloadStatus.FAILED -> InstallStatus.FAILED download.status == DownloadStatus.CANCELLED -> InstallStatus.PENDING