diff --git a/app/src/main/java/com/aurora/store/compose/ui/commons/MicroGInstallerPrerequisiteDialog.kt b/app/src/main/java/com/aurora/store/compose/ui/commons/MicroGInstallerPrerequisiteDialog.kt new file mode 100644 index 000000000..7e18156a0 --- /dev/null +++ b/app/src/main/java/com/aurora/store/compose/ui/commons/MicroGInstallerPrerequisiteDialog.kt @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2026 Aurora OSS + * SPDX-FileCopyrightText: 2026 The Calyx Institute + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.aurora.store.compose.ui.commons + +import android.content.ActivityNotFoundException +import android.content.ComponentName +import android.content.Intent +import android.util.Log +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewWrapper +import com.aurora.Constants.PACKAGE_NAME_GMS +import com.aurora.extensions.TAG +import com.aurora.store.R +import com.aurora.store.compose.preview.ThemePreviewProvider + +private const val MICROG_SETTINGS_ACTIVITY = "org.microg.gms.ui.SettingsActivity" + +/** + * Dialog informing users about the prerequisite for using the microG installer + * @param onConfirm Callback on confirmation + * @param onDismiss Callback on dismissal + */ +@Composable +fun MicroGInstallerPrerequisiteDialog(onConfirm: () -> Unit = {}, onDismiss: () -> Unit = {}) { + val context = LocalContext.current + + AlertDialog( + title = { Text(text = stringResource(R.string.microg_installer_prerequisite_title)) }, + text = { + Column( + verticalArrangement = Arrangement.spacedBy( + dimensionResource(R.dimen.spacing_small) + ) + ) { + Text(text = stringResource(R.string.microg_installer_prerequisite_desc)) + OutlinedButton ( + onClick = { + try { + context.startActivity( + Intent().apply { + component = ComponentName( + PACKAGE_NAME_GMS, + MICROG_SETTINGS_ACTIVITY + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + ) + } catch (_: ActivityNotFoundException) { + Log.i(TAG, "Unable to launch microG settings") + } + } + ) { + Text(text = stringResource(R.string.microg_installer_open_settings)) + } + } + }, + onDismissRequest = onDismiss, + confirmButton = { + TextButton(onClick = onConfirm) { + Text(text = stringResource(R.string.action_ok)) + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text(text = stringResource(R.string.action_cancel)) + } + } + ) +} + +@PreviewWrapper(ThemePreviewProvider::class) +@Preview +@Composable +private fun MicroGInstallerPrerequisiteDialogPreview() { + MicroGInstallerPrerequisiteDialog() +} diff --git a/app/src/main/java/com/aurora/store/compose/ui/preferences/installation/InstallerScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/preferences/installation/InstallerScreen.kt index 09a9a367b..cd8519a52 100644 --- a/app/src/main/java/com/aurora/store/compose/ui/preferences/installation/InstallerScreen.kt +++ b/app/src/main/java/com/aurora/store/compose/ui/preferences/installation/InstallerScreen.kt @@ -15,7 +15,9 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource @@ -28,6 +30,7 @@ import com.aurora.store.R import com.aurora.store.compose.composable.InstallerListItem import com.aurora.store.compose.composable.TopAppBar import com.aurora.store.compose.preview.ThemePreviewProvider +import com.aurora.store.compose.ui.commons.MicroGInstallerPrerequisiteDialog import com.aurora.store.data.installer.AppInstaller import com.aurora.store.data.installer.SessionInstaller import com.aurora.store.data.model.Installer @@ -61,6 +64,17 @@ private fun ScreenContent( onInstallerSelected: (installer: Installer) -> Unit = {} ) { val snackBarHostState = remember { snackBarHostState } + var showMicroGPrerequisite by remember { mutableStateOf(false) } + + if (showMicroGPrerequisite) { + MicroGInstallerPrerequisiteDialog( + onConfirm = { + showMicroGPrerequisite = false + onInstallerSelected(Installer.MICROG) + }, + onDismiss = { showMicroGPrerequisite = false } + ) + } Scaffold( snackbarHost = { @@ -82,7 +96,13 @@ private fun ScreenContent( InstallerListItem( installerInfo = installerInfo, isSelected = installerInfo.installer == currentInstaller, - onClick = { onInstallerSelected(installerInfo.installer) } + onClick = { + if (installerInfo.installer == Installer.MICROG) { + showMicroGPrerequisite = true + } else { + onInstallerSelected(installerInfo.installer) + } + } ) } } diff --git a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt index c5f73c51d..0e3d7e053 100644 --- a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt @@ -41,6 +41,7 @@ import com.aurora.store.data.installer.base.IInstaller import com.aurora.store.data.model.Installer import com.aurora.store.data.model.InstallerInfo import com.aurora.store.util.PackageUtil +import com.aurora.store.util.PackageUtil.hasMicroGCompanion import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID import com.topjohnwu.superuser.Shell @@ -83,7 +84,7 @@ class AppInstaller @Inject constructor( if (hasAuroraService(context)) ServiceInstaller.installerInfo else null, if (hasAppManager(context)) AMInstaller.installerInfo else null, if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null, - if (hasMicroGInstaller(context)) MicroGInstaller.installerInfo else null + if (hasMicroGCompanion(context)) MicroGInstaller.installerInfo else null ) /** @@ -154,6 +155,7 @@ class AppInstaller @Inject constructor( false } + // TODO: Use microG's proposed API instead of relying on a hardcoded metadata flag that can be misleading (e.g. user can enable the installer from UI) fun hasMicroGInstaller(context: Context): Boolean { if (!PackageUtil.hasMicroGCompanion(context)) return false return try { @@ -236,7 +238,7 @@ class AppInstaller @Inject constructor( defaultInstaller } - Installer.MICROG -> if (hasMicroGInstaller(context)) { + Installer.MICROG -> if (hasMicroGCompanion(context)) { microGInstaller } else { defaultInstaller diff --git a/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt index aa5fabf1e..e72fcf4cb 100644 --- a/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt @@ -31,6 +31,7 @@ import com.aurora.store.data.installer.base.InstallerBase import com.aurora.store.data.model.Installer import com.aurora.store.data.model.InstallerInfo import com.aurora.store.data.room.download.Download +import com.aurora.store.util.PackageUtil.hasMicroGCompanion import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import javax.inject.Singleton @@ -68,7 +69,7 @@ class MicroGInstaller @Inject constructor( Log.i(TAG, "${download.packageName} already queued") } - AppInstaller.hasMicroGInstaller(context) -> { + hasMicroGCompanion(context) -> { Log.i(TAG, "Received microG install request for ${download.packageName}") val files = getFiles(download.packageName, download.versionCode) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bf7280757..dcc13a6a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -469,6 +469,9 @@ microG is no longer installed. Run setup again to keep things working smoothly. Requires microG companion app to be installed Helps you bypass App Integrity (installer only) check + Enable microG installer + Before using the microG installer, please ensure you have enabled it.\n\nPlay Store services → ⋮ → App Installer Settings → Allow App Installation + Open microG settings Full-featured open source package manager Requires App Manager, need adb/root mode to install when miui optimization is on Using system APIs directly with adb/root privileges