[#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:
Carter Jernigan 2023-02-09 06:47:04 -05:00 committed by GitHub
parent e4b51bef59
commit a7d7de0451
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 50 additions and 149 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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