[#745] Set min API to 27
* Add Android min SDK API level check test --------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
parent
e4b51bef59
commit
a7d7de0451
|
@ -304,7 +304,7 @@ fladle {
|
|||
val FIREBASE_TEST_LAB_MAX_SDK = 33
|
||||
|
||||
val minSdkVersion = run {
|
||||
val buildMinSdk = project.properties["ANDROID_APP_MIN_SDK_VERSION"].toString().toInt()
|
||||
val buildMinSdk = project.properties["ANDROID_MIN_SDK_VERSION"].toString().toInt()
|
||||
buildMinSdk.coerceAtLeast(FIREBASE_TEST_LAB_MIN_SDK).toString()
|
||||
}
|
||||
val targetSdkVersion = run {
|
||||
|
|
|
@ -6,9 +6,10 @@ import androidx.test.core.app.ApplicationProvider
|
|||
import androidx.test.filters.SmallTest
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.lessThanOrEqualTo
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class TargetApiTest {
|
||||
class AndroidApiTest {
|
||||
|
||||
@Test
|
||||
@SmallTest
|
||||
|
@ -21,4 +22,16 @@ class TargetApiTest {
|
|||
lessThanOrEqualTo(Build.VERSION_CODES.TIRAMISU)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@SmallTest
|
||||
fun checkMinApi() {
|
||||
// This test case prevents accidental release of the app with a different API level than we
|
||||
// have currently set in gradle.properties. It could impact the app's functionality. Don't
|
||||
// change this unless you're absolutely sure we're ready to set a new API level.
|
||||
assertEquals(
|
||||
ApplicationProvider.getApplicationContext<Application>().applicationInfo.minSdkVersion,
|
||||
Build.VERSION_CODES.O_MR1
|
||||
)
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ pluginManager.withPlugin("com.android.application") {
|
|||
configureBaseExtension(isLibrary = false)
|
||||
|
||||
defaultConfig {
|
||||
minSdk = project.property("ANDROID_APP_MIN_SDK_VERSION").toString().toInt()
|
||||
minSdk = project.property("ANDROID_MIN_SDK_VERSION").toString().toInt()
|
||||
targetSdk = project.property("ANDROID_TARGET_SDK_VERSION").toString().toInt()
|
||||
|
||||
// en_XA and ar_XB are pseudolocales for debugging.
|
||||
|
@ -31,7 +31,7 @@ pluginManager.withPlugin("com.android.library") {
|
|||
configureBaseExtension(isLibrary = true)
|
||||
|
||||
defaultConfig {
|
||||
minSdk = project.property("ANDROID_LIB_MIN_SDK_VERSION").toString().toInt()
|
||||
minSdk = project.property("ANDROID_MIN_SDK_VERSION").toString().toInt()
|
||||
// This is deprecated but we don't have a replacement for the instrumentation APKs yet
|
||||
targetSdk = project.property("ANDROID_TARGET_SDK_VERSION").toString().toInt()
|
||||
|
||||
|
@ -60,7 +60,7 @@ pluginManager.withPlugin("com.android.test") {
|
|||
configureBaseExtension(isLibrary = true)
|
||||
|
||||
defaultConfig {
|
||||
minSdk = project.property("ANDROID_LIB_MIN_SDK_VERSION").toString().toInt()
|
||||
minSdk = project.property("ANDROID_MIN_SDK_VERSION").toString().toInt()
|
||||
// This is deprecated but we don't have a replacement for the instrumentation APKs yet
|
||||
targetSdk = project.property("ANDROID_TARGET_SDK_VERSION").toString().toInt()
|
||||
|
||||
|
@ -130,11 +130,7 @@ fun com.android.build.gradle.BaseExtension.configureBaseExtension(isLibrary: Boo
|
|||
val MANAGED_DEVICES_MIN_SDK = 27
|
||||
|
||||
val testDeviceMinSdkVersion = run {
|
||||
val buildMinSdk = if (isLibrary) {
|
||||
project.properties["ANDROID_LIB_MIN_SDK_VERSION"].toString().toInt()
|
||||
} else {
|
||||
project.properties["ANDROID_APP_MIN_SDK_VERSION"].toString().toInt()
|
||||
}
|
||||
val buildMinSdk = project.properties["ANDROID_MIN_SDK_VERSION"].toString().toInt()
|
||||
buildMinSdk.coerceAtLeast(MANAGED_DEVICES_MIN_SDK)
|
||||
}
|
||||
val testDeviceMaxSdkVersion = project.properties["ANDROID_TARGET_SDK_VERSION"].toString().toInt()
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
import com.android.build.gradle.internal.cxx.configure.buildTypeOf
|
||||
import com.android.build.gradle.internal.dsl.decorator.androidPluginDslDecorator
|
||||
|
||||
// Emulator WTF has min and max values that might differ from our project's
|
||||
// These are determined by `ew-cli --models`
|
||||
|
||||
|
@ -24,18 +21,8 @@ pluginManager.withPlugin("wtf.emulator.gradle") {
|
|||
environmentVariables.set(mapOf("useTestStorageService" to "false"))
|
||||
}
|
||||
|
||||
val buildMinSdk = if (pluginManager.hasPlugin("com.android.application")) {
|
||||
project.properties["ANDROID_APP_MIN_SDK_VERSION"].toString().toInt()
|
||||
} else if (pluginManager.hasPlugin("com.android.test")) {
|
||||
project.properties["ANDROID_APP_MIN_SDK_VERSION"].toString().toInt()
|
||||
} else if (pluginManager.hasPlugin("com.android.library")) {
|
||||
project.properties["ANDROID_LIB_MIN_SDK_VERSION"].toString().toInt()
|
||||
} else {
|
||||
throw IllegalArgumentException("Unsupported plugin type. Make sure that the plugin type you've added is" +
|
||||
" supported by ${this.javaClass.name}.")
|
||||
}
|
||||
|
||||
val moduleMinSdkVersion = run {
|
||||
val minSdkVersion = run {
|
||||
val buildMinSdk = project.properties["ANDROID_MIN_SDK_VERSION"].toString().toInt()
|
||||
buildMinSdk.coerceAtLeast(EMULATOR_WTF_MIN_SDK).toString()
|
||||
}
|
||||
val targetSdkVersion = run {
|
||||
|
@ -45,7 +32,7 @@ pluginManager.withPlugin("wtf.emulator.gradle") {
|
|||
|
||||
devices.set(
|
||||
listOf(
|
||||
mapOf("model" to "Pixel2", "version" to moduleMinSdkVersion),
|
||||
mapOf("model" to "Pixel2", "version" to minSdkVersion),
|
||||
mapOf("model" to "Pixel2", "version" to targetSdkVersion)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -151,7 +151,7 @@ fladle {
|
|||
val minSdkVersion = run {
|
||||
// Fladle will use the app APK as the additional APK, so we have to
|
||||
// use the app's minSdkVersion here.
|
||||
val buildMinSdk = project.properties["ANDROID_APP_MIN_SDK_VERSION"].toString().toInt()
|
||||
val buildMinSdk = project.properties["ANDROID_MIN_SDK_VERSION"].toString().toInt()
|
||||
buildMinSdk.coerceAtLeast(FIREBASE_TEST_LAB_MIN_SDK).toString()
|
||||
}
|
||||
val targetSdkVersion = run {
|
||||
|
|
|
@ -92,11 +92,7 @@ SDK_INCLUDED_BUILD_PATH=
|
|||
BIP_39_INCLUDED_BUILD_PATH=
|
||||
|
||||
# Versions
|
||||
# A lower version on the libraries helps to ensure some degree of backwards compatiblity, for the project
|
||||
# as a whole. But a higher version on the app ensures that we aren't directly supporting users
|
||||
# with old devices.
|
||||
ANDROID_LIB_MIN_SDK_VERSION=24
|
||||
ANDROID_APP_MIN_SDK_VERSION=27
|
||||
ANDROID_MIN_SDK_VERSION=27
|
||||
ANDROID_TARGET_SDK_VERSION=33
|
||||
ANDROID_COMPILE_SDK_VERSION=33
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package co.electriccoin.zcash.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.filters.SdkSuppress
|
||||
import androidx.test.filters.SmallTest
|
||||
import co.electriccoin.zcash.preference.test.fixture.StringDefaultPreferenceFixture
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
@ -68,7 +66,6 @@ class EncryptedPreferenceProviderTest {
|
|||
// e.g. the directory path and the fact the preferences are stored as XML
|
||||
@Test
|
||||
@SmallTest
|
||||
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
|
||||
fun verify_no_plaintext() = runBlocking {
|
||||
val expectedValue = StringDefaultPreferenceFixture.DEFAULT_VALUE + "extra"
|
||||
|
||||
|
|
|
@ -15,12 +15,6 @@ object AndroidApiVersion {
|
|||
return Build.VERSION.SDK_INT >= sdk
|
||||
}
|
||||
|
||||
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N)
|
||||
val isAtLeastN = isAtLeast(Build.VERSION_CODES.N)
|
||||
|
||||
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)
|
||||
val isAtLeastO = isAtLeast(Build.VERSION_CODES.O)
|
||||
|
||||
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
|
||||
val isAtLeastP = isAtLeast(Build.VERSION_CODES.P)
|
||||
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
package co.electriccoin.zcash.spackle
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.StrictMode
|
||||
|
||||
object StrictModeCompat {
|
||||
|
||||
fun enableStrictMode(isCrashOnViolation: Boolean) {
|
||||
configureStrictMode(isCrashOnViolation)
|
||||
|
||||
// Workaround for Android bug
|
||||
// https://issuetracker.google.com/issues/36951662
|
||||
// Not needed if target O_MR1 and running on O_MR1
|
||||
// Don't really need to check target, because of Google Play enforcement on targetSdkVersion for app updates
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) {
|
||||
Handler(Looper.getMainLooper()).postAtFrontOfQueue {
|
||||
configureStrictMode(isCrashOnViolation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
|
@ -38,39 +25,26 @@ object StrictModeCompat {
|
|||
)
|
||||
|
||||
// Don't enable missing network tags, because those are noisy.
|
||||
if (AndroidApiVersion.isAtLeastO) {
|
||||
StrictMode.setVmPolicy(
|
||||
StrictMode.VmPolicy.Builder().apply {
|
||||
detectActivityLeaks()
|
||||
detectCleartextNetwork()
|
||||
detectContentUriWithoutPermission()
|
||||
detectFileUriExposure()
|
||||
detectLeakedClosableObjects()
|
||||
detectLeakedRegistrationObjects()
|
||||
detectLeakedSqlLiteObjects()
|
||||
if (AndroidApiVersion.isAtLeastP) {
|
||||
// Disable because this is mostly flagging Android X and Play Services
|
||||
// builder.detectNonSdkApiUsage();
|
||||
}
|
||||
StrictMode.setVmPolicy(
|
||||
StrictMode.VmPolicy.Builder().apply {
|
||||
detectActivityLeaks()
|
||||
detectCleartextNetwork()
|
||||
detectContentUriWithoutPermission()
|
||||
detectFileUriExposure()
|
||||
detectLeakedClosableObjects()
|
||||
detectLeakedRegistrationObjects()
|
||||
detectLeakedSqlLiteObjects()
|
||||
if (AndroidApiVersion.isAtLeastP) {
|
||||
// Disable because this is mostly flagging Android X and Play Services
|
||||
// builder.detectNonSdkApiUsage();
|
||||
}
|
||||
|
||||
if (isCrashOnViolation) {
|
||||
penaltyDeath()
|
||||
} else {
|
||||
penaltyLog()
|
||||
}
|
||||
}.build()
|
||||
)
|
||||
} else {
|
||||
StrictMode.setVmPolicy(
|
||||
StrictMode.VmPolicy.Builder().apply {
|
||||
detectAll()
|
||||
if (isCrashOnViolation) {
|
||||
penaltyDeath()
|
||||
} else {
|
||||
penaltyLog()
|
||||
}
|
||||
}.build()
|
||||
)
|
||||
}
|
||||
if (isCrashOnViolation) {
|
||||
penaltyDeath()
|
||||
} else {
|
||||
penaltyLog()
|
||||
}
|
||||
}.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package co.electriccoin.zcash.test
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.KeyguardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Before
|
||||
|
@ -15,21 +13,18 @@ import org.junit.Before
|
|||
// Originally hoped to put this into ZcashUiTestRunner, although it causes reporting of test results to fail
|
||||
open class UiTestPrerequisites {
|
||||
@Before
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
|
||||
fun verifyPrerequisites() {
|
||||
assertScreenIsOn()
|
||||
assertKeyguardIsUnlocked()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
|
||||
fun assertScreenIsOn() {
|
||||
if (!isScreenOn()) {
|
||||
throw AssertionError("Screen must be on for Android UI tests to run") // $NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
|
||||
private fun isScreenOn(): Boolean {
|
||||
val powerService = ApplicationProvider.getApplicationContext<Context>()
|
||||
.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package co.electriccoin.zcash.ui.design.compat
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.FontRes
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import co.electriccoin.zcash.spackle.AndroidApiVersion
|
||||
import co.electriccoin.zcash.ui.design.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
object FontCompat {
|
||||
fun isFontPrefetchNeeded() = !AndroidApiVersion.isAtLeastO
|
||||
|
||||
suspend fun prefetchFontsLegacy(context: Context) {
|
||||
prefetchFontLegacy(context, R.font.zboto)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-fetches fonts on Android N (API 25) and below.
|
||||
*/
|
||||
/*
|
||||
* ResourcesCompat is used implicitly by Compose on older Android versions.
|
||||
* The backwards compatibility library performs disk IO and then
|
||||
* caches the results. This moves that IO off the main thread, to prevent ANRs and
|
||||
* jank during app startup.
|
||||
*/
|
||||
private suspend fun prefetchFontLegacy(context: Context, @FontRes fontRes: Int) =
|
||||
withContext(Dispatchers.IO) {
|
||||
ResourcesCompat.getFont(context, fontRes)
|
||||
}
|
||||
}
|
|
@ -13,10 +13,8 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavHostController
|
||||
import co.electriccoin.zcash.ui.common.BindCompLocalProvider
|
||||
import co.electriccoin.zcash.ui.design.compat.FontCompat
|
||||
import co.electriccoin.zcash.ui.design.component.ConfigurationOverride
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.Override
|
||||
|
@ -28,7 +26,6 @@ import co.electriccoin.zcash.ui.screen.onboarding.WrapOnboarding
|
|||
import co.electriccoin.zcash.ui.screen.warning.WrapNotEnoughSpace
|
||||
import co.electriccoin.zcash.ui.screen.warning.viewmodel.StorageCheckViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
@ -49,14 +46,7 @@ class MainActivity : ComponentActivity() {
|
|||
|
||||
setupSplashScreen()
|
||||
|
||||
if (FontCompat.isFontPrefetchNeeded()) {
|
||||
lifecycleScope.launch {
|
||||
FontCompat.prefetchFontsLegacy(applicationContext)
|
||||
setupUiContent()
|
||||
}
|
||||
} else {
|
||||
setupUiContent()
|
||||
}
|
||||
setupUiContent()
|
||||
}
|
||||
|
||||
private fun setupSplashScreen() {
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package co.electriccoin.zcash.ui.screen.support.model
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import cash.z.ecc.sdk.ext.ui.model.MonetarySeparators
|
||||
import co.electriccoin.zcash.global.StorageChecker
|
||||
import co.electriccoin.zcash.spackle.AndroidApiVersion
|
||||
import java.util.Locale
|
||||
|
||||
class EnvironmentInfo(val locale: Locale, val monetarySeparators: MonetarySeparators, val usableStorageMegabytes: Int) {
|
||||
|
@ -20,20 +18,12 @@ class EnvironmentInfo(val locale: Locale, val monetarySeparators: MonetarySepara
|
|||
suspend fun new(context: Context): EnvironmentInfo {
|
||||
val usableStorage = StorageChecker.checkAvailableStorageMegabytes()
|
||||
|
||||
return EnvironmentInfo(currentLocale(context), MonetarySeparators.current(), usableStorage)
|
||||
return EnvironmentInfo(
|
||||
context.resources.configuration.locales[0],
|
||||
MonetarySeparators.current(),
|
||||
usableStorage
|
||||
)
|
||||
}
|
||||
|
||||
private fun currentLocale(context: Context) = if (AndroidApiVersion.isAtLeastN) {
|
||||
currentLocaleNPlus(context)
|
||||
} else {
|
||||
currentLocaleLegacy(context)
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private fun currentLocaleNPlus(context: Context) = context.resources.configuration.locales[0]
|
||||
|
||||
@Suppress("Deprecation")
|
||||
private fun currentLocaleLegacy(context: Context) = context.resources.configuration.locale
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue