From e4dda6e12ee0f6c793031c5b64f548abaf183fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C9=91rry=20Shiv=C9=91m?= Date: Sun, 12 May 2024 13:11:30 +0530 Subject: [PATCH] fix: Disable app locale setting on MIUI due to Xiaomi's broken implementation (#133) --------- Signed-off-by: starry-shivam --- .../settings/composables/SettingsScreen.kt | 12 ++++- .../java/com/starry/greenstash/utils/Utils.kt | 47 +++++++++++++++++-- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/starry/greenstash/ui/screens/settings/composables/SettingsScreen.kt b/app/src/main/java/com/starry/greenstash/ui/screens/settings/composables/SettingsScreen.kt index 66faff3..82b3a31 100644 --- a/app/src/main/java/com/starry/greenstash/ui/screens/settings/composables/SettingsScreen.kt +++ b/app/src/main/java/com/starry/greenstash/ui/screens/settings/composables/SettingsScreen.kt @@ -25,6 +25,7 @@ package com.starry.greenstash.ui.screens.settings.composables +import android.annotation.SuppressLint import android.content.Intent import android.net.Uri import android.os.Build @@ -332,6 +333,7 @@ private fun ThemePickerDialog( } } +@SuppressLint("InlinedApi") @Composable private fun LocaleSettings(viewModel: SettingsViewModel) { val context = LocalContext.current @@ -360,8 +362,14 @@ private fun LocaleSettings(viewModel: SettingsViewModel) { SettingsContainer { SettingsCategory(title = stringResource(id = R.string.locales_setting_title)) - // App locale setting is only available on Android 13+. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // App locale setting is only available on Android 13+ + // Also, it's not functional on MIUI devices even on Android 13, + // Thanks to Xiaomi's broken implementation of standard Android APIs. + // See: https://github.com/Pool-Of-Tears/GreenStash/issues/130 for more information. + val shouldShowAppLocaleSetting = remember { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !Utils.isMiui() + } + if (shouldShowAppLocaleSetting) { SettingsItem(title = stringResource(id = R.string.app_locale_setting), description = stringResource(id = R.string.app_locale_setting_desc), icon = Icons.Filled.Language, diff --git a/app/src/main/java/com/starry/greenstash/utils/Utils.kt b/app/src/main/java/com/starry/greenstash/utils/Utils.kt index 82b2e78..97eed3f 100644 --- a/app/src/main/java/com/starry/greenstash/utils/Utils.kt +++ b/app/src/main/java/com/starry/greenstash/utils/Utils.kt @@ -33,6 +33,9 @@ import android.os.Build import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader import java.math.RoundingMode import java.text.DecimalFormat import java.text.DecimalFormatSymbols @@ -43,12 +46,14 @@ import java.util.Currency import java.util.Locale import java.util.TimeZone + /** * A collection of utility functions. */ object Utils { - /** Get validated number from the text. + /** + * Get validated number from the text. * * @param text The text to validate * @return The validated number @@ -69,7 +74,8 @@ object Utils { } } - /** Round the decimal number to two decimal places. + /** + * Round the decimal number to two decimal places. * * @param number The number to round * @return The rounded number @@ -81,7 +87,8 @@ object Utils { return df.format(number).toDouble() } - /** Format currency based on the currency code. + /** + * Format currency based on the currency code. * * @param amount The amount to format * @param currencyCode The currency code @@ -121,7 +128,8 @@ object Utils { } - /** Get the epoch time from the LocalDateTime. + /** + * Get the epoch time from the LocalDateTime. * * @param dateTime The LocalDateTime object * @return The epoch time @@ -135,7 +143,8 @@ object Utils { return dateTime.atZone(timeZone).toInstant().toEpochMilli() } - /** Open the web link in the browser. + /** + * Open the web link in the browser. * * @param context The context * @param url The URL to open @@ -150,4 +159,32 @@ object Utils { } } + /** + * Check if the device is running on MIUI. + * + * By default, HyperOS is excluded from the check. + * If you want to include HyperOS in the check, set excludeHyperOS to false. + * + * @param excludeHyperOS Whether to exclude HyperOS + * @return True if the device is running on MIUI, false otherwise + */ + fun isMiui(excludeHyperOS: Boolean = true): Boolean { + val isMiui = !getProperty("ro.miui.ui.version.name").isNullOrBlank() + val isHyperOS = !getProperty("ro.mi.os.version.name").isNullOrBlank() + return isMiui && (!excludeHyperOS || !isHyperOS) + } + + // Private function to get the property value from build.prop. + private fun getProperty(property: String): String? { + return try { + Runtime.getRuntime().exec("getprop $property").inputStream.use { input -> + BufferedReader(InputStreamReader(input), 1024).readLine() + } + } catch (e: IOException) { + e.printStackTrace() + null + } + } + + } \ No newline at end of file