diff --git a/app/src/main/java/com/geode/launcher/preferences/SettingsActivity.kt b/app/src/main/java/com/geode/launcher/preferences/SettingsActivity.kt index 9c55594..032f134 100644 --- a/app/src/main/java/com/geode/launcher/preferences/SettingsActivity.kt +++ b/app/src/main/java/com/geode/launcher/preferences/SettingsActivity.kt @@ -35,10 +35,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -405,11 +407,73 @@ fun SettingsScreen( ) } - Text( - stringResource(R.string.preference_launcher_version, BuildConfig.VERSION_NAME), - style = Typography.labelSmall, - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp) - ) + OptionsGroup(stringResource(R.string.preference_category_about)) { + val clipboard = LocalClipboardManager.current + + OptionsButton( + stringResource(R.string.preference_launcher_version_name), + stringResource(R.string.preference_launcher_version_description, BuildConfig.VERSION_NAME), + displayInline = true + ) { + clipboard.setText(AnnotatedString(context.getString( + R.string.preference_launcher_version, + BuildConfig.VERSION_NAME + ))) + } + + OptionsButton( + stringResource(R.string.preference_loader_version_name), + stringResource(R.string.preference_loader_version_description, currentRelease ?: "unknown"), + displayInline = true + ) { + clipboard.setText(AnnotatedString(context.getString( + R.string.preference_loader_version, + currentRelease ?: "unknown" + ))) + } + + val gameInstalled = remember { + GamePackageUtils.isGameInstalled(context.packageManager) + } + + if (gameInstalled) { + val gameVersion = remember { + GamePackageUtils.getUnifiedVersionName(context.packageManager) + } + + val gameSource = remember { + context.getString(when (GamePackageUtils.identifyGameSource(context.packageManager)) { + GamePackageUtils.GameSource.GOOGLE -> R.string.preference_game_source_google + GamePackageUtils.GameSource.AMAZON -> R.string.preference_game_source_amazon + else -> R.string.preference_game_source_unknown + }) + } + + OptionsButton( + stringResource(R.string.preference_game_version_name), + stringResource(R.string.preference_game_version_description, gameVersion, gameSource), + displayInline = true + ) { + clipboard.setText(AnnotatedString(context.getString( + R.string.preference_game_version, + gameVersion, + gameSource + ))) + } + + OptionsButton( + stringResource(R.string.preference_architecture_name), + stringResource(R.string.preference_architecture_description, Build.MODEL, LaunchUtils.applicationArchitecture), + displayInline = true + ) { + clipboard.setText(AnnotatedString(context.getString( + R.string.preference_architecture, + Build.MODEL, + LaunchUtils.applicationArchitecture + ))) + } + } + } } } ) diff --git a/app/src/main/java/com/geode/launcher/preferences/SettingsComponents.kt b/app/src/main/java/com/geode/launcher/preferences/SettingsComponents.kt index cbd4bc4..b9cf85b 100644 --- a/app/src/main/java/com/geode/launcher/preferences/SettingsComponents.kt +++ b/app/src/main/java/com/geode/launcher/preferences/SettingsComponents.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog @@ -297,18 +298,22 @@ fun SelectDialog( } @Composable -fun OptionsButton(title: String, description: String? = null, icon: (@Composable () -> Unit)? = null, onClick: () -> Unit) { +fun OptionsButton(title: String, description: String? = null, icon: (@Composable () -> Unit)? = null, displayInline: Boolean = false, onClick: () -> Unit) { OptionsCard( title = { OptionsTitle( title = title, - description = description, + description = description.takeIf { !displayInline }, icon = icon ) }, modifier = Modifier .clickable(onClick = onClick, role = Role.Button) - ) { } + ) { + if (displayInline && description != null) { + Text(description, textAlign = TextAlign.End) + } + } } @Composable diff --git a/app/src/main/java/com/geode/launcher/utils/GamePackageUtils.kt b/app/src/main/java/com/geode/launcher/utils/GamePackageUtils.kt index 6be71e6..daddb56 100644 --- a/app/src/main/java/com/geode/launcher/utils/GamePackageUtils.kt +++ b/app/src/main/java/com/geode/launcher/utils/GamePackageUtils.kt @@ -113,24 +113,40 @@ object GamePackageUtils { } private const val GAME_CERTIFICATE_HASH = "f5e7d8284d72c461a5f022d0cf755df101c3bb1e69cbe241bc1aef2cc5610a43" + private const val AMAZON_CERTIFICATE_HASH = "1f228081e4d66e006887d4ba0f3d40e96a80c758b84231f11cd5c1c9aef6048f" + + private fun validateCertificate(certificate: ByteArray): GameSource = when (val hash = certificate.toByteString().sha256().hex()) { + GAME_CERTIFICATE_HASH -> GameSource.GOOGLE + AMAZON_CERTIFICATE_HASH -> GameSource.AMAZON + else -> { + println("Encountered certificate hash: $hash") + GameSource.UNKNOWN + } + } - private fun validateCertificate(certificate: ByteArray): Boolean = - certificate.toByteString().sha256().hex() == GAME_CERTIFICATE_HASH + enum class GameSource { + UNKNOWN, GOOGLE, AMAZON + } - fun identifyGameLegitimacy(packageManager: PackageManager): Boolean { + fun identifyGameSource(packageManager: PackageManager): GameSource { @Suppress("DEPRECATION") val certificates = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { val game = packageManager.getPackageInfo(Constants.PACKAGE_NAME, PackageManager.GET_SIGNING_CERTIFICATES) val signingInfo = game.signingInfo - signingInfo?.signingCertificateHistory ?: return false + signingInfo?.signingCertificateHistory ?: return GameSource.UNKNOWN } else { val game = packageManager.getPackageInfo(Constants.PACKAGE_NAME, PackageManager.GET_SIGNATURES) game.signatures } - return certificates?.any { + return certificates?.map { validateCertificate(it.toByteArray()) - } ?: false + }?.firstOrNull { + it != GameSource.UNKNOWN + } ?: GameSource.UNKNOWN } + + fun identifyGameLegitimacy(packageManager: PackageManager) = + identifyGameSource(packageManager) != GameSource.UNKNOWN } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 78c0a37..0889343 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -149,9 +149,29 @@ Pre-release Nightly + About + + Android Launcher + v%1$s + Android Launcher v%1$s + + Geode + %1$s + Geode %1$s + + Geometry Dash + %1$s (%2$s) + Geometry Dash %1$s (%2$s) + Google + Amazon + Unknown + + Device + %1$s (%2$s) + %1$s (%2$s) + Check for updates Current loader version: %1$s - Geode Launcher v%1$s Update failed. See logs for more details. No updates found. Geode has been updated!