Enable microG Installer and add microG installer prerequisite dialog

Partially addresses: #1485

Show the microG installer whenever the companion app is present instead
of relying on the misleading vending_apps_install metadata flag, and warn
users to enable it from microG settings before use. The dialog also offers
a shortcut to open microG settings.

microG only exposes the top-level settings activity; the App Installer
Settings screen is a Navigation fragment with no deep link, so the dialog
guides users through the remaining steps.
This commit is contained in:
Rahul Patel
2026-06-03 02:02:29 +05:30
parent f1c5a1deb8
commit fd350c739c
5 changed files with 120 additions and 4 deletions

View File

@@ -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()
}

View File

@@ -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)
}
}
)
}
}

View File

@@ -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

View File

@@ -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)

View File

@@ -469,6 +469,9 @@
<string name="microg_removed_auth_warning">microG is no longer installed. Run setup again to keep things working smoothly.</string>
<string name="microg_installer_subtitle">Requires microG companion app to be installed</string>
<string name="microg_installer_desc">Helps you bypass App Integrity (installer only) check</string>
<string name="microg_installer_prerequisite_title" translatable="false">Enable microG installer</string>
<string name="microg_installer_prerequisite_desc" translatable="false">Before using the microG installer, please ensure you have enabled it.\n\nPlay Store services → ⋮ → App Installer Settings → Allow App Installation</string>
<string name="microg_installer_open_settings" translatable="false">Open microG settings</string>
<string name="am_installer_subtitle">Full-featured open source package manager</string>
<string name="am_installer_desc">Requires App Manager, need adb/root mode to install when miui optimization is on</string>
<string name="shizuku_installer_subtitle">Using system APIs directly with adb/root privileges</string>