Merge branch 'dev'
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 5,
|
||||
"identityHash": "d5da6e54113409ba811bafebc85632e6",
|
||||
"identityHash": "82935f33f6fe476bd752dd3643095d69",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "download",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `isInstalled` INTEGER NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `size` INTEGER NOT NULL, `id` INTEGER NOT NULL, `downloadStatus` TEXT NOT NULL, `progress` INTEGER NOT NULL, `speed` INTEGER NOT NULL, `timeRemaining` INTEGER NOT NULL, `totalFiles` INTEGER NOT NULL, `downloadedFiles` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, `targetSdk` INTEGER NOT NULL, `downloadedAt` INTEGER NOT NULL, PRIMARY KEY(`packageName`))",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `isInstalled` INTEGER NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `size` INTEGER NOT NULL, `id` INTEGER NOT NULL, `downloadStatus` TEXT NOT NULL, `progress` INTEGER NOT NULL, `speed` INTEGER NOT NULL, `timeRemaining` INTEGER NOT NULL, `totalFiles` INTEGER NOT NULL, `downloadedFiles` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, `targetSdk` INTEGER NOT NULL, `downloadedAt` INTEGER NOT NULL, `requiresGMS` INTEGER NOT NULL, PRIMARY KEY(`packageName`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "packageName",
|
||||
@@ -57,7 +57,7 @@
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadStatus",
|
||||
"fieldPath": "status",
|
||||
"columnName": "downloadStatus",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
@@ -115,6 +115,12 @@
|
||||
"columnName": "downloadedAt",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "requiresGMS",
|
||||
"columnName": "requiresGMS",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
@@ -122,9 +128,7 @@
|
||||
"columnNames": [
|
||||
"packageName"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "favourite",
|
||||
@@ -166,9 +170,7 @@
|
||||
"columnNames": [
|
||||
"packageName"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"tableName": "update",
|
||||
@@ -270,15 +272,12 @@
|
||||
"columnNames": [
|
||||
"packageName"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd5da6e54113409ba811bafebc85632e6')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '82935f33f6fe476bd752dd3643095d69')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class InstallerStatusReceiver : BaseInstallerStatusReceiver() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun postStatus(status: Int, packageName: String?, extra: String?, context: Context) {
|
||||
override fun postStatus(status: Int, packageName: String, extra: String?, context: Context) {
|
||||
super.postStatus(status, packageName, extra, context)
|
||||
|
||||
if (::apiClient.isInitialized && apiClient.isConnected) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.aurora.extensions.isHuawei
|
||||
|
||||
object FlavouredUtil : IFlavouredUtil {
|
||||
|
||||
override val defaultDispensers = emptySet()
|
||||
override val defaultDispensers: Set<String> = emptySet()
|
||||
|
||||
override fun promptMicroGInstall(context: Context): Boolean {
|
||||
return isHuawei &&
|
||||
|
||||
@@ -69,4 +69,9 @@ object Constants {
|
||||
const val PACKAGE_NAME_GMS = "com.google.android.gms"
|
||||
const val PACKAGE_NAME_PLAY_STORE = "com.android.vending"
|
||||
const val PACKAGE_NAME_APP_GALLERY = "com.huawei.appmarket"
|
||||
|
||||
// FLAVOURS
|
||||
const val FLAVOUR_VANILLA = "vanilla"
|
||||
const val FLAVOUR_HUAWEI = "huawei"
|
||||
const val FLAVOUR_PRELOAD = "preload"
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -32,21 +33,22 @@ import com.aurora.extensions.browse
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.compose.preview.PreviewTemplate
|
||||
import com.aurora.store.data.model.Link
|
||||
import com.aurora.store.viewmodel.onboarding.MicroGUIState
|
||||
|
||||
/**
|
||||
* Composable to display suggestion to install microG
|
||||
* @param modifier Modifier for the composable
|
||||
* @param isTOSChecked Whether the TOS checkbox is checked
|
||||
* @param onInstall Callback when user requests installing microG bundle
|
||||
*/
|
||||
@Composable
|
||||
fun MicroG(
|
||||
modifier: Modifier = Modifier,
|
||||
isTOSChecked: Boolean = false,
|
||||
onInstall: () -> Unit = {}
|
||||
uiState: MicroGUIState,
|
||||
onInstall: () -> Unit = {},
|
||||
onTOSChecked: (Boolean) -> Unit = {}
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var isChecked by rememberSaveable { mutableStateOf(isTOSChecked) }
|
||||
var isChecked by rememberSaveable { mutableStateOf(false) }
|
||||
val links = listOf(
|
||||
Link(
|
||||
id = 2,
|
||||
@@ -101,7 +103,6 @@ fun MicroG(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = dimensionResource(R.dimen.padding_xlarge)),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small))
|
||||
) {
|
||||
Row(
|
||||
@@ -110,7 +111,14 @@ fun MicroG(
|
||||
dimensionResource(R.dimen.padding_small)
|
||||
)
|
||||
) {
|
||||
Checkbox(checked = isChecked, onCheckedChange = { isChecked = !isChecked })
|
||||
Checkbox(
|
||||
checked = isChecked,
|
||||
onCheckedChange = {
|
||||
isChecked = it
|
||||
onTOSChecked(it)
|
||||
},
|
||||
enabled = !uiState.isInstalled && !uiState.isDownloading
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_gms_agreement),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
@@ -118,9 +126,21 @@ fun MicroG(
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
Button(onClick = onInstall, enabled = isChecked) {
|
||||
Button(
|
||||
onClick = onInstall,
|
||||
enabled = isChecked && !uiState.isDownloading && !uiState.isInstalled,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.action_install_microG)
|
||||
text = if (uiState.isDownloading)
|
||||
stringResource(R.string.action_installing)
|
||||
else
|
||||
stringResource(R.string.action_install_microG)
|
||||
)
|
||||
}
|
||||
if (uiState.isDownloading) {
|
||||
LinearProgressIndicator(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -131,6 +151,6 @@ fun MicroG(
|
||||
@Composable
|
||||
private fun MicroGPreview() {
|
||||
PreviewTemplate {
|
||||
MicroG(isTOSChecked = true)
|
||||
MicroG(uiState = MicroGUIState())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ private fun ScreenContentApp(
|
||||
is ExtraScreen.MicroG -> MicroGScreen(
|
||||
packageName = app.packageName,
|
||||
onNavigateUp = ::onNavigateBack,
|
||||
onIgnore = { onInstall(ignoreMicroG = true) }
|
||||
onIgnore = { onInstall(ignoreMicroG = it) }
|
||||
)
|
||||
|
||||
is Screen.DevProfile -> DevProfileScreen(
|
||||
|
||||
@@ -42,13 +42,14 @@ import com.aurora.store.compose.preview.PreviewTemplate
|
||||
import com.aurora.store.data.model.PermissionType
|
||||
import com.aurora.store.data.providers.PermissionProvider
|
||||
import com.aurora.store.viewmodel.details.AppDetailsViewModel
|
||||
import com.aurora.store.viewmodel.onboarding.MicroGUIState
|
||||
import com.aurora.store.viewmodel.onboarding.MicroGViewModel
|
||||
|
||||
@Composable
|
||||
fun MicroGScreen(
|
||||
packageName: String,
|
||||
onNavigateUp: () -> Unit,
|
||||
onIgnore: () -> Unit,
|
||||
onIgnore: (Boolean) -> Unit,
|
||||
appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName),
|
||||
viewModel: MicroGViewModel = hiltViewModel(),
|
||||
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
|
||||
@@ -61,6 +62,7 @@ fun MicroGScreen(
|
||||
|
||||
ScreenContent(
|
||||
topAppBarTitle = topAppBarTitle,
|
||||
uiState = viewModel.uiState,
|
||||
onNavigateUp = onNavigateUp,
|
||||
onInstall = { viewModel.downloadMicroG() },
|
||||
onIgnore = onIgnore
|
||||
@@ -70,9 +72,10 @@ fun MicroGScreen(
|
||||
@Composable
|
||||
private fun ScreenContent(
|
||||
topAppBarTitle: String? = null,
|
||||
uiState: MicroGUIState = MicroGUIState(),
|
||||
onNavigateUp: () -> Unit = {},
|
||||
onInstall: () -> Unit = {},
|
||||
onIgnore: () -> Unit = {},
|
||||
onIgnore: (Boolean) -> Unit = {},
|
||||
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
@@ -98,13 +101,17 @@ private fun ScreenContent(
|
||||
modifier = Modifier.weight(1F),
|
||||
onInstall = {
|
||||
when {
|
||||
PermissionProvider.isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS) -> {
|
||||
PermissionProvider.isGranted(
|
||||
context,
|
||||
PermissionType.INSTALL_UNKNOWN_APPS
|
||||
) -> {
|
||||
onInstall()
|
||||
}
|
||||
|
||||
else -> context.toast(R.string.permissions_denied)
|
||||
}
|
||||
}
|
||||
},
|
||||
uiState = uiState
|
||||
)
|
||||
|
||||
Row(
|
||||
@@ -124,10 +131,14 @@ private fun ScreenContent(
|
||||
|
||||
Button(
|
||||
modifier = Modifier.weight(1F),
|
||||
onClick = onIgnore
|
||||
onClick = { onIgnore(uiState.isInstalled) },
|
||||
enabled = !uiState.isDownloading
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.action_ignore),
|
||||
text = if (uiState.isInstalled)
|
||||
stringResource(R.string.action_install)
|
||||
else
|
||||
stringResource(R.string.action_ignore),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
@@ -27,17 +27,27 @@ import com.aurora.store.compose.composable.MicroG
|
||||
import com.aurora.store.compose.preview.PreviewTemplate
|
||||
import com.aurora.store.data.model.PermissionType
|
||||
import com.aurora.store.data.providers.PermissionProvider
|
||||
import com.aurora.store.viewmodel.onboarding.MicroGUIState
|
||||
import com.aurora.store.viewmodel.onboarding.MicroGViewModel
|
||||
|
||||
@Composable
|
||||
fun MicroGPage(viewModel: MicroGViewModel = hiltViewModel()) {
|
||||
fun MicroGPage(
|
||||
onMicrogTOSChecked: (Boolean) -> Unit = {},
|
||||
viewModel: MicroGViewModel = hiltViewModel(),
|
||||
) {
|
||||
ScreenContent(
|
||||
onInstall = { viewModel.downloadMicroG() }
|
||||
uiState = viewModel.uiState,
|
||||
onInstall = { viewModel.downloadMicroG() },
|
||||
onMicrogTOSChecked = onMicrogTOSChecked,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScreenContent(onInstall: () -> Unit = {}) {
|
||||
private fun ScreenContent(
|
||||
uiState: MicroGUIState,
|
||||
onInstall: () -> Unit = {},
|
||||
onMicrogTOSChecked: (Boolean) -> Unit = {}
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Column(
|
||||
@@ -58,7 +68,7 @@ private fun ScreenContent(onInstall: () -> Unit = {}) {
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_title_gsf_desc),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
@@ -73,7 +83,9 @@ private fun ScreenContent(onInstall: () -> Unit = {}) {
|
||||
|
||||
else -> context.toast(R.string.permissions_denied)
|
||||
}
|
||||
}
|
||||
},
|
||||
uiState = uiState,
|
||||
onTOSChecked = onMicrogTOSChecked
|
||||
)
|
||||
}
|
||||
|
||||
@@ -83,6 +95,8 @@ private fun ScreenContent(onInstall: () -> Unit = {}) {
|
||||
@Composable
|
||||
private fun MicroGPagePreview() {
|
||||
PreviewTemplate {
|
||||
ScreenContent()
|
||||
ScreenContent(
|
||||
uiState = MicroGUIState(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
@@ -25,11 +26,11 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import com.aurora.extensions.isWindowCompact
|
||||
import com.aurora.store.R
|
||||
@@ -37,22 +38,25 @@ import com.aurora.store.compose.composable.Logo
|
||||
import com.aurora.store.compose.composable.PageIndicator
|
||||
import com.aurora.store.compose.preview.PreviewTemplate
|
||||
import com.aurora.store.compose.ui.onboarding.navigation.OnboardingPage
|
||||
import com.aurora.store.util.FlavouredUtil
|
||||
import com.aurora.store.viewmodel.onboarding.OnboardingUiState
|
||||
import com.aurora.store.viewmodel.onboarding.OnboardingViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun OnboardingScreen(viewModel: OnboardingViewModel = hiltViewModel()) {
|
||||
val context = LocalContext.current
|
||||
val pages = listOfNotNull(
|
||||
OnboardingPage.WELCOME,
|
||||
OnboardingPage.PERMISSIONS,
|
||||
if (FlavouredUtil.promptMicroGInstall(context)) OnboardingPage.MICRO_G else null
|
||||
if (viewModel.isMicroGPromptRequired) OnboardingPage.MICRO_G else null
|
||||
)
|
||||
|
||||
ScreenContent(
|
||||
pages = pages,
|
||||
onFinishOnboarding = { viewModel.finishOnboarding() }
|
||||
onFinishOnboarding = {
|
||||
viewModel.finishOnboarding()
|
||||
},
|
||||
uiState = viewModel.uiState,
|
||||
onMicrogTOSChecked = viewModel::onMicrogTOSChecked
|
||||
)
|
||||
}
|
||||
|
||||
@@ -60,6 +64,8 @@ fun OnboardingScreen(viewModel: OnboardingViewModel = hiltViewModel()) {
|
||||
private fun ScreenContent(
|
||||
pages: List<OnboardingPage> = emptyList(),
|
||||
onFinishOnboarding: () -> Unit = {},
|
||||
uiState: OnboardingUiState,
|
||||
onMicrogTOSChecked: (Boolean) -> Unit,
|
||||
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
|
||||
) {
|
||||
val pagerState = rememberPagerState { pages.size }
|
||||
@@ -70,7 +76,7 @@ private fun ScreenContent(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SetupActions() {
|
||||
fun SetupActions(uiState: OnboardingUiState) {
|
||||
val horizontalButtonPadding = when {
|
||||
windowAdaptiveInfo.isWindowCompact -> dimensionResource(R.dimen.padding_medium)
|
||||
else -> dimensionResource(R.dimen.padding_xlarge)
|
||||
@@ -119,6 +125,7 @@ private fun ScreenContent(
|
||||
|
||||
Button(
|
||||
modifier = buttonWidthModifier,
|
||||
enabled = !isFinalPage() || (!uiState.isMicroBundleChecked || uiState.isMicroGBundleInstalled),
|
||||
onClick = {
|
||||
when {
|
||||
isFinalPage() -> onFinishOnboarding()
|
||||
@@ -145,6 +152,7 @@ private fun ScreenContent(
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
modifier = Modifier.height(64.dp),
|
||||
title = {
|
||||
PageIndicator(totalPages = pages.size, currentPage = pagerState.currentPage)
|
||||
}
|
||||
@@ -175,12 +183,12 @@ private fun ScreenContent(
|
||||
when (pages[page]) {
|
||||
OnboardingPage.WELCOME -> WelcomePage()
|
||||
OnboardingPage.PERMISSIONS -> PermissionsPage()
|
||||
OnboardingPage.MICRO_G -> MicroGPage()
|
||||
OnboardingPage.MICRO_G -> MicroGPage(onMicrogTOSChecked = onMicrogTOSChecked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetupActions()
|
||||
SetupActions(uiState)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +198,9 @@ private fun ScreenContent(
|
||||
private fun OnboardingScreenPreview() {
|
||||
PreviewTemplate {
|
||||
ScreenContent(
|
||||
pages = listOf(OnboardingPage.WELCOME, OnboardingPage.PERMISSIONS)
|
||||
pages = listOf(OnboardingPage.WELCOME, OnboardingPage.PERMISSIONS),
|
||||
uiState = OnboardingUiState(),
|
||||
onMicrogTOSChecked = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ private fun PageContent(
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_permission_select),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
@@ -112,7 +112,7 @@ private fun PageContent(onAboutAurora: () -> Unit = {}) {
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.onboarding_welcome_select),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
@@ -166,6 +166,10 @@ class AppInstaller @Inject constructor(
|
||||
private val defaultInstaller: IInstaller
|
||||
get() = sessionInstaller
|
||||
|
||||
fun getMicroGInstaller(): IInstaller {
|
||||
return microGInstaller
|
||||
}
|
||||
|
||||
fun getPreferredInstaller(): IInstaller {
|
||||
return when (getCurrentInstaller(context)) {
|
||||
Installer.SESSION -> sessionInstaller
|
||||
|
||||
@@ -26,6 +26,10 @@ object MigrationHelper {
|
||||
override fun migrate(db: SupportSQLiteDatabase) = migrateFrom4To5(db)
|
||||
}
|
||||
|
||||
val MIGRATION_5_6 = object : Migration(5, 6) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) = migrateFrom5To6(db)
|
||||
}
|
||||
|
||||
private const val TAG = "MigrationHelper"
|
||||
|
||||
private fun migrateFrom1To2(database: SupportSQLiteDatabase) {
|
||||
@@ -83,4 +87,21 @@ object MigrationHelper {
|
||||
database.endTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add requiresGMS column to download table for checking if app requires GMS to install.
|
||||
*/
|
||||
private fun migrateFrom5To6(database: SupportSQLiteDatabase) {
|
||||
database.beginTransaction()
|
||||
try {
|
||||
database.execSQL(
|
||||
"ALTER TABLE `download` ADD COLUMN requiresGMS INTEGER NOT NULL DEFAULT 0"
|
||||
)
|
||||
database.setTransactionSuccessful()
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed while migrating from database version 5 to 6", exception)
|
||||
} finally {
|
||||
database.endTransaction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.aurora.store.data.room.MigrationHelper.MIGRATION_1_2
|
||||
import com.aurora.store.data.room.MigrationHelper.MIGRATION_2_3
|
||||
import com.aurora.store.data.room.MigrationHelper.MIGRATION_3_4
|
||||
import com.aurora.store.data.room.MigrationHelper.MIGRATION_4_5
|
||||
import com.aurora.store.data.room.MigrationHelper.MIGRATION_5_6
|
||||
import com.aurora.store.data.room.download.DownloadConverter
|
||||
import com.aurora.store.data.room.download.DownloadDao
|
||||
import com.aurora.store.data.room.favourite.FavouriteDao
|
||||
@@ -30,7 +31,7 @@ object RoomModule {
|
||||
downloadConverter: DownloadConverter
|
||||
): AuroraDatabase {
|
||||
return Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE)
|
||||
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5)
|
||||
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
|
||||
.addTypeConverter(downloadConverter)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.os.Parcelable
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.aurora.extensions.requiresGMS
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.PlayFile
|
||||
import com.aurora.store.data.model.DownloadStatus
|
||||
@@ -35,7 +36,8 @@ data class Download(
|
||||
var fileList: List<PlayFile>,
|
||||
val sharedLibs: List<SharedLib>,
|
||||
val targetSdk: Int = 1,
|
||||
val downloadedAt: Long = 0
|
||||
val downloadedAt: Long = 0,
|
||||
val requiresGMS: Boolean = false
|
||||
) : Parcelable {
|
||||
val isFinished get() = status in DownloadStatus.finished
|
||||
val isRunning get() = status in DownloadStatus.running
|
||||
@@ -61,7 +63,8 @@ data class Download(
|
||||
app.fileList.filterNot { it.url.isBlank() },
|
||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) },
|
||||
app.targetSdk,
|
||||
Date().time
|
||||
Date().time,
|
||||
app.requiresGMS()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.work.ForegroundInfo
|
||||
import androidx.work.WorkInfo.Companion.STOP_REASON_CANCELLED_BY_APP
|
||||
import androidx.work.WorkInfo.Companion.STOP_REASON_USER
|
||||
import androidx.work.WorkerParameters
|
||||
import com.aurora.Constants.FLAVOUR_HUAWEI
|
||||
import com.aurora.extensions.copyTo
|
||||
import com.aurora.extensions.isPAndAbove
|
||||
import com.aurora.extensions.isQAndAbove
|
||||
@@ -28,6 +29,7 @@ import com.aurora.gplayapi.data.models.PlayFile
|
||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||
import com.aurora.gplayapi.network.IHttpClient
|
||||
import com.aurora.store.AuroraApp
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.helper.DownloadHelper
|
||||
@@ -41,6 +43,7 @@ import com.aurora.store.data.room.download.Download
|
||||
import com.aurora.store.data.room.download.DownloadDao
|
||||
import com.aurora.store.util.CertUtil
|
||||
import com.aurora.store.util.NotificationUtil
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import com.aurora.store.util.PathUtil
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
@@ -88,8 +91,11 @@ class DownloadWorker @AssistedInject constructor(
|
||||
inner class NoNetworkException : Exception(context.getString(R.string.title_no_network))
|
||||
inner class NothingToDownloadException : Exception(context.getString(R.string.purchase_no_file))
|
||||
inner class DownloadFailedException : Exception(context.getString(R.string.download_failed))
|
||||
inner class DownloadCancelledException : Exception(context.getString(R.string.download_canceled))
|
||||
inner class VerificationFailedException : Exception(context.getString(R.string.verification_failed))
|
||||
inner class DownloadCancelledException :
|
||||
Exception(context.getString(R.string.download_canceled))
|
||||
|
||||
inner class VerificationFailedException :
|
||||
Exception(context.getString(R.string.verification_failed))
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
super.doWork()
|
||||
@@ -198,6 +204,9 @@ class DownloadWorker @AssistedInject constructor(
|
||||
private suspend fun onSuccess(): Result {
|
||||
return withContext(NonCancellable) {
|
||||
return@withContext try {
|
||||
if (BuildConfig.FLAVOR == FLAVOUR_HUAWEI && download.requiresGMS && PackageUtil.hasMicroGCompanion(context))
|
||||
appInstaller.getMicroGInstaller().install(download)
|
||||
else
|
||||
appInstaller.getPreferredInstaller().install(download)
|
||||
Result.success()
|
||||
} catch (exception: Exception) {
|
||||
|
||||
@@ -5,31 +5,60 @@
|
||||
|
||||
package com.aurora.store.viewmodel.onboarding
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.aurora.Constants.PACKAGE_NAME_GMS
|
||||
import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE
|
||||
import com.aurora.gplayapi.data.models.PlayFile
|
||||
import com.aurora.store.AuroraApp
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.helper.DownloadHelper
|
||||
import com.aurora.store.data.room.suite.ExternalApk
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
data class MicroGUIState(
|
||||
var isDownloading: Boolean = false,
|
||||
var isInstalled: Boolean = false
|
||||
)
|
||||
|
||||
@HiltViewModel
|
||||
class MicroGViewModel @Inject constructor(
|
||||
@ApplicationContext
|
||||
private val context: Context,
|
||||
private val downloadHelper: DownloadHelper
|
||||
) : ViewModel() {
|
||||
|
||||
companion object {
|
||||
private const val MICROG_DOWNLOAD_URL =
|
||||
"https://github.com/microg/GmsCore/releases/download"
|
||||
private const val MICROG_VERSION = "v0.3.6.244735"
|
||||
private const val GMS_VERSION_CODE = 244735012
|
||||
private const val COMPANION_VERSION_CODE = 84022612
|
||||
private const val MICROG_VERSION = "v0.3.11.250932"
|
||||
private const val GMS_VERSION_CODE = 250932022
|
||||
private const val COMPANION_VERSION_CODE = 84022622
|
||||
}
|
||||
|
||||
init {
|
||||
AuroraApp.events.installerEvent.onEach {
|
||||
when (it) {
|
||||
is InstallerEvent.Installed -> confirmBundleInstall(it.packageName)
|
||||
else -> {}
|
||||
}
|
||||
}.launchIn(AuroraApp.scope)
|
||||
}
|
||||
|
||||
var uiState: MicroGUIState by mutableStateOf(MicroGUIState())
|
||||
private set
|
||||
|
||||
private val microGServiceApk = ExternalApk(
|
||||
packageName = PACKAGE_NAME_GMS,
|
||||
versionCode = GMS_VERSION_CODE.toLong(),
|
||||
@@ -41,8 +70,8 @@ class MicroGViewModel @Inject constructor(
|
||||
PlayFile(
|
||||
url = "$MICROG_DOWNLOAD_URL/$MICROG_VERSION/$PACKAGE_NAME_GMS-$GMS_VERSION_CODE-hw.apk",
|
||||
name = "$PACKAGE_NAME_GMS-$GMS_VERSION_CODE-hw.apk",
|
||||
size = 32509431,
|
||||
sha256 = "2f14df2974811b576bfafa6167a97e3b3032f2bd6e6ec3887a833fd2fa350dda"
|
||||
size = 92386474,
|
||||
sha256 = "2894a93544a8d7ca8f6ca96e7cc697647a7e0862165b6a02f8cd26822759b9cc"
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -58,16 +87,33 @@ class MicroGViewModel @Inject constructor(
|
||||
PlayFile(
|
||||
url = "$MICROG_DOWNLOAD_URL/$MICROG_VERSION/$PACKAGE_NAME_PLAY_STORE-$COMPANION_VERSION_CODE-hw.apk",
|
||||
name = "$PACKAGE_NAME_PLAY_STORE-$COMPANION_VERSION_CODE-hw.apk",
|
||||
size = 3915551,
|
||||
sha256 = "6835b09016cef0fc3469b4a36b1720427ad3f81161cf20b188f0dadb5f8594e1"
|
||||
size = 4626291,
|
||||
sha256 = "b9623b8da8791c7e887efca941434b20e517c8a42ca4fda713625957edcc84eb"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
fun downloadMicroG() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
downloadHelper.enqueueStandalone(microGServiceApk)
|
||||
if (microGCompanionApk.isInstalled(context)) {
|
||||
AuroraApp.events.send(InstallerEvent.Installed(PACKAGE_NAME_PLAY_STORE))
|
||||
} else {
|
||||
downloadHelper.enqueueStandalone(microGCompanionApk)
|
||||
uiState = uiState.copy(isDownloading = true)
|
||||
}
|
||||
|
||||
if (microGServiceApk.isInstalled(context)) {
|
||||
AuroraApp.events.send(InstallerEvent.Installed(PACKAGE_NAME_GMS))
|
||||
} else {
|
||||
downloadHelper.enqueueStandalone(microGServiceApk)
|
||||
uiState = uiState.copy(isDownloading = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun confirmBundleInstall(packageName: String) {
|
||||
if (PackageUtil.isMicroGBundleInstalled(context)) {
|
||||
uiState = uiState.copy(isInstalled = true, isDownloading = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,24 @@ package com.aurora.store.viewmodel.onboarding
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.aurora.Constants.FLAVOUR_HUAWEI
|
||||
import com.aurora.Constants.PACKAGE_NAME_GMS
|
||||
import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE
|
||||
import com.aurora.extensions.areNotificationsEnabled
|
||||
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
||||
import com.aurora.store.AuroraApp
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.helper.UpdateHelper
|
||||
import com.aurora.store.data.model.UpdateMode
|
||||
import com.aurora.store.data.providers.BlacklistProvider
|
||||
import com.aurora.store.data.work.CacheWorker
|
||||
import com.aurora.store.util.FlavouredUtil
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB
|
||||
@@ -32,19 +43,51 @@ import com.aurora.store.util.save
|
||||
import com.jakewharton.processphoenix.ProcessPhoenix
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import javax.inject.Inject
|
||||
|
||||
data class OnboardingUiState(
|
||||
val isMicroBundleChecked: Boolean = false,
|
||||
val isMicroGBundleInstalled: Boolean = false
|
||||
)
|
||||
|
||||
@HiltViewModel
|
||||
class OnboardingViewModel @Inject constructor(
|
||||
val updateHelper: UpdateHelper,
|
||||
val blacklistProvider: BlacklistProvider,
|
||||
@ApplicationContext private val context: Context
|
||||
) : ViewModel() {
|
||||
|
||||
private val TAG = OnboardingViewModel::class.java.simpleName
|
||||
|
||||
val isMicroGPromptRequired = FlavouredUtil.promptMicroGInstall(context)
|
||||
|
||||
var uiState by mutableStateOf(OnboardingUiState())
|
||||
private set
|
||||
|
||||
init {
|
||||
AuroraApp.events.installerEvent.onEach {
|
||||
when (it) {
|
||||
is InstallerEvent.Installed -> confirmBundleInstall()
|
||||
else -> {}
|
||||
}
|
||||
}.launchIn(AuroraApp.scope)
|
||||
}
|
||||
|
||||
fun onMicrogTOSChecked(value: Boolean) {
|
||||
uiState = uiState.copy(isMicroBundleChecked = value)
|
||||
}
|
||||
|
||||
fun finishOnboarding() {
|
||||
Log.i(TAG, "Finishing onboarding with defaults")
|
||||
context.saveDefaultPreferences()
|
||||
|
||||
if (BuildConfig.FLAVOR == FLAVOUR_HUAWEI) {
|
||||
blacklistProvider.blacklist(PACKAGE_NAME_GMS)
|
||||
blacklistProvider.blacklist(PACKAGE_NAME_PLAY_STORE)
|
||||
}
|
||||
|
||||
setupAutoUpdates()
|
||||
CacheWorker.scheduleAutomatedCacheCleanup(context)
|
||||
Preferences.putBooleanNow(context, PREFERENCE_INTRO, true)
|
||||
@@ -53,6 +96,12 @@ class OnboardingViewModel @Inject constructor(
|
||||
ProcessPhoenix.triggerRebirth(context)
|
||||
}
|
||||
|
||||
private fun confirmBundleInstall() {
|
||||
if (PackageUtil.isMicroGBundleInstalled(context)) {
|
||||
uiState = uiState.copy(isMicroGBundleInstalled = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupAutoUpdates() {
|
||||
val updateMode = when {
|
||||
context.isIgnoringBatteryOptimizations() -> UpdateMode.CHECK_AND_INSTALL
|
||||
|
||||
@@ -25,7 +25,8 @@ dependencyResolutionManagement {
|
||||
// Only included in huawei variants
|
||||
maven("https://developer.huawei.com/repo/") {
|
||||
content {
|
||||
includeModule("com.huawei.hms", "ag-coreservice")
|
||||
includeGroup("com.huawei.hms")
|
||||
includeGroup("com.huawei.android.hms")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user