Skip to content

Commit 2fecd0f

Browse files
committed
Feat: Android 16 QPR2 (API 36.1)
Signed-off-by: imknown <imknown@qq.com>
1 parent c7f2047 commit 2fecd0f

7 files changed

Lines changed: 164 additions & 70 deletions

File tree

app/src/main/java/net/imknown/android/forefrontinfo/ui/common/AndroidVersionExt.kt

Lines changed: 84 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,77 @@ package net.imknown.android.forefrontinfo.ui.common
33
import android.app.ActivityManager
44
import android.content.Context
55
import android.os.Build
6+
import android.os.ext.SdkExtensions
7+
import android.util.Log
8+
import androidx.annotation.RequiresApi
69
import androidx.core.content.ContextCompat
10+
import net.imknown.android.forefrontinfo.base.extension.fullMessage
711
import net.imknown.android.forefrontinfo.ui.home.model.Lld
12+
import kotlin.reflect.KClass
813

914
private const val CODENAME_RELEASE = "REL"
1015

11-
fun isAtLeastStableAndroid6() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
12-
fun isAtLeastStableAndroid7() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
13-
fun isAtLeastStableAndroid8() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
14-
fun isAtLeastStableAndroid8P1() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1
15-
fun isAtLeastStableAndroid9() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
16-
fun isAtLeastStableAndroid10() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
17-
fun isAtLeastStableAndroid11() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
18-
fun isAtLeastStableAndroid12() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
19-
fun isAtLeastStableAndroid13() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
20-
// fun isAtLeastStableAndroid14() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
21-
// fun isAtLeastStableAndroid15() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM
22-
fun isAtLeastStableAndroid16() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA
16+
/** See: [Build.VERSION].RESOURCES_SDK_INT */
17+
private fun listCodes(kClass: KClass<*>): List<Pair<String?, Int>> {
18+
val fields = try {
19+
kClass.java.fields
20+
} catch (e: Exception) {
21+
Log.w(kClass.simpleName, "Failed to get ${kClass::simpleName} fields. ${e.fullMessage}")
22+
emptyArray()
23+
}
24+
return fields.mapNotNull {
25+
try {
26+
it.isAccessible = true
27+
28+
val value = it.getInt(null)
29+
if (value != Build.VERSION_CODES.CUR_DEVELOPMENT) {
30+
Pair(it.name, value)
31+
} else {
32+
null
33+
}
34+
} catch (e: Exception) {
35+
Log.w(kClass.simpleName, "Failed to get $it. ${e.fullMessage}")
36+
null
37+
}
38+
}.sortedBy { it.second }
39+
}
40+
41+
private fun latestApiOrNull(kClass: KClass<*>) = listCodes(kClass).lastOrNull()?.second
42+
43+
val sdkInt by lazy {
44+
if (isStableAndroid()) {
45+
Build.VERSION.SDK_INT
46+
} else {
47+
latestApiOrNull(Build.VERSION_CODES::class)
48+
?: Build.VERSION.SDK_INT
49+
}
50+
}
51+
52+
val sdkIntFull by lazy {
53+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
54+
if (isStableAndroid()) {
55+
Build.VERSION.SDK_INT_FULL
56+
} else {
57+
latestApiOrNull(Build.VERSION_CODES_FULL::class)
58+
?: Build.VERSION.SDK_INT_FULL
59+
}
60+
} else {
61+
sdkInt
62+
}
63+
}
64+
65+
fun isAtLeastStableAndroid6() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M || sdkInt >= Build.VERSION_CODES.M
66+
fun isAtLeastStableAndroid7() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N || sdkInt >= Build.VERSION_CODES.N
67+
fun isAtLeastStableAndroid8() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O || sdkInt >= Build.VERSION_CODES.O
68+
fun isAtLeastStableAndroid8P1() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 || sdkInt >= Build.VERSION_CODES.O_MR1
69+
fun isAtLeastStableAndroid9() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P || sdkInt >= Build.VERSION_CODES.P
70+
fun isAtLeastStableAndroid10() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q || sdkInt >= Build.VERSION_CODES.Q
71+
fun isAtLeastStableAndroid11() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R || sdkInt >= Build.VERSION_CODES.R
72+
fun isAtLeastStableAndroid12() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S || sdkInt >= Build.VERSION_CODES.S
73+
fun isAtLeastStableAndroid13() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU || sdkInt >= Build.VERSION_CODES.TIRAMISU
74+
// fun isAtLeastStableAndroid14() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE || sdkInt >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
75+
// fun isAtLeastStableAndroid15() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM || sdkInt >= Build.VERSION_CODES.VANILLA_ICE_CREAM
76+
fun isAtLeastStableAndroid16() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA || sdkInt >= Build.VERSION_CODES.BAKLAVA
2377

2478
fun isStableAndroid() = Build.VERSION.CODENAME == CODENAME_RELEASE
2579
fun isPreviewAndroid() = !isStableAndroid()
@@ -28,20 +82,25 @@ fun isLatestStableAndroid(lld: Lld) = isStableAndroid()
2882
&& Build.VERSION.SDK_INT >= lld.android.stable.api.toInt()
2983

3084
fun isLatestPreviewAndroid(lld: Lld) = isPreviewAndroid()
31-
&& getAndroidVersionName() >= lld.android.preview.name[0].toString()
85+
&& sdkInt >= lld.android.preview.api.toInt()
3286

3387
fun isSupportedByUpstreamAndroid(lld: Lld) = isStableAndroid()
3488
&& Build.VERSION.SDK_INT >= lld.android.support.api.toInt()
3589

36-
/** For minSdk ≥ Android 11, use [Build.VERSION.RELEASE_OR_CODENAME] (`ro.build.version.release_or_codename`) */
37-
fun getAndroidVersionName(): String = if (isStableAndroid()) {
38-
Build.VERSION.RELEASE
39-
} else {
40-
if (isAtLeastStableAndroid13()) {
41-
"${Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY}, "
90+
/**
91+
* [Build.VERSION.RELEASE_OR_CODENAME]: Android 11+
92+
* [Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY]: Android 13+
93+
* [Build.VERSION.CODENAME]
94+
*/
95+
fun getAndroidDessertPreview(): String = if (isAtLeastStableAndroid13()) {
96+
val codename = Build.VERSION.CODENAME
97+
codename + if (codename != Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY) {
98+
", " + Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY
4299
} else {
43100
""
44-
} + Build.VERSION.CODENAME
101+
}
102+
} else {
103+
Build.VERSION.CODENAME
45104
}
46105

47106
fun Context.isGoEdition() = isAtLeastStableAndroid8P1() && isLowRamDevice()
@@ -50,11 +109,11 @@ private fun Context.isLowRamDevice() = ContextCompat.getSystemService(
50109
this, ActivityManager::class.java
51110
)?.isLowRamDevice == true
52111

53-
fun getAndroidApiLevel() = if (isStableAndroid()) {
54-
Build.VERSION.SDK_INT
55-
} else {
56-
Build.VERSION_CODES.CUR_DEVELOPMENT
57-
}
112+
@RequiresApi(Build.VERSION_CODES.BAKLAVA)
113+
fun getAndroidApiLevelMinor(sdkIntFull: Int): Int = Build.getMinorSdkVersion(sdkIntFull)
114+
115+
@RequiresApi(Build.VERSION_CODES.R)
116+
fun getSdkExtension(extension: Int): Int = SdkExtensions.getExtensionVersion(extension)
58117

59118
//fun Context.getAndroidApiLevelDynamic() = packageManager.getApplicationInfo(
60119
// "android", 0

app/src/main/java/net/imknown/android/forefrontinfo/ui/home/model/Lld.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
package net.imknown.android.forefrontinfo.ui.home.model
22

33
import androidx.annotation.Keep
4+
import kotlinx.serialization.EncodeDefault
45
import kotlinx.serialization.Serializable
56

7+
const val CODENAME_NONE = ""
8+
const val CODENAME_CANARY = "CANARY"
9+
const val EXTENSION_NONE = 0
10+
const val SCHEME_VERSION = 1
11+
612
@Keep
713
@Serializable
814
data class Lld(
@@ -13,10 +19,6 @@ data class Lld(
1319
val toybox: Toyboxes,
1420
val webView: WebViews
1521
) {
16-
companion object {
17-
const val SCHEME_VERSION = 1
18-
}
19-
2022
// https://source.android.com/security/enhancements/enhancements9
2123
// https://source.android.com/setup/start/p-release-notes
2224
// https://developer.android.com/about/versions/10
@@ -56,14 +58,21 @@ data class Lld(
5658
// https://ci.android.com
5759
// https://developer.android.com/about/canary
5860
val preview: Android,
59-
val internal: Android
61+
val internal: Android,
62+
val known: List<Android>
6063
) {
6164
@Keep
6265
@Serializable
6366
data class Android(
64-
val name: String,
6567
val api: String,
68+
val apiFull: String,
6669
val version: String,
70+
/** Dessert */
71+
val name: String,
72+
// https://android.googlesource.com/platform/build/release/+/refs/heads/main/flag_values/trunk_staging/RELEASE_PLATFORM_VERSION_KNOWN_CODENAMES.textproto
73+
@EncodeDefault val codename: String = CODENAME_NONE,
74+
@EncodeDefault val extension: Int = EXTENSION_NONE,
75+
/** Deprecated: "Preview" used to be: "$[version] $[phase]" */
6776
val phase: String? = null
6877
)
6978

app/src/main/java/net/imknown/android/forefrontinfo/ui/home/repository/HomeRepository.kt

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,32 @@ import net.imknown.android.forefrontinfo.base.extension.formatToLocalZonedDateti
1919
import net.imknown.android.forefrontinfo.base.extension.fullMessage
2020
import net.imknown.android.forefrontinfo.ui.base.list.MyModel
2121
import net.imknown.android.forefrontinfo.ui.base.list.toColoredMyModel
22-
import net.imknown.android.forefrontinfo.ui.common.getAndroidApiLevel
23-
import net.imknown.android.forefrontinfo.ui.common.getAndroidVersionName
22+
import net.imknown.android.forefrontinfo.ui.common.getAndroidApiLevelMinor
23+
import net.imknown.android.forefrontinfo.ui.common.getAndroidDessertPreview
2424
import net.imknown.android.forefrontinfo.ui.common.getBooleanProperty
25+
import net.imknown.android.forefrontinfo.ui.common.getSdkExtension
2526
import net.imknown.android.forefrontinfo.ui.common.getShellResult
2627
import net.imknown.android.forefrontinfo.ui.common.getStringProperty
2728
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid10
2829
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid11
2930
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid12
3031
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid13
32+
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid16
3133
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid6
3234
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid7
3335
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid8
3436
import net.imknown.android.forefrontinfo.ui.common.isAtLeastStableAndroid9
3537
import net.imknown.android.forefrontinfo.ui.common.isGoEdition
3638
import net.imknown.android.forefrontinfo.ui.common.isLatestPreviewAndroid
3739
import net.imknown.android.forefrontinfo.ui.common.isLatestStableAndroid
38-
import net.imknown.android.forefrontinfo.ui.common.isPreviewAndroid
40+
import net.imknown.android.forefrontinfo.ui.common.isStableAndroid
3941
import net.imknown.android.forefrontinfo.ui.common.isSupportedByUpstreamAndroid
42+
import net.imknown.android.forefrontinfo.ui.common.sdkInt
43+
import net.imknown.android.forefrontinfo.ui.common.sdkIntFull
4044
import net.imknown.android.forefrontinfo.ui.home.datasource.AndroidDataSource
4145
import net.imknown.android.forefrontinfo.ui.home.datasource.LldDataSource
4246
import net.imknown.android.forefrontinfo.ui.home.datasource.MountDataSource
47+
import net.imknown.android.forefrontinfo.ui.home.model.EXTENSION_NONE
4348
import net.imknown.android.forefrontinfo.ui.home.model.Lld
4449
import net.imknown.android.forefrontinfo.ui.settings.datasource.AppInfoDataSource
4550
import java.io.File
@@ -76,49 +81,64 @@ class HomeRepository(
7681

7782
fun detectAndroid(lld: Lld): MyModel {
7883
// region [Mine]
79-
var myAndroidVersionName = getAndroidVersionName()
84+
val myApiFull = if (isAtLeastStableAndroid16()) {
85+
"$sdkInt.${getAndroidApiLevelMinor(sdkIntFull)}"
86+
} else {
87+
sdkInt.toString()
88+
}
89+
90+
var myNameAndDessert = if (isStableAndroid()) {
91+
val dessert = lld.android.known.find {
92+
it.api.toInt() == sdkInt
93+
}?.name
94+
?: MyApplication.getMyString(android.R.string.unknownName)
95+
Build.VERSION.RELEASE + ", " + dessert
96+
} else {
97+
val android = lld.android.known.find {
98+
it.apiFull == myApiFull
99+
}
100+
if (android != null) {
101+
val preview = MyApplication.getMyString(R.string.android_info_preview)
102+
android.version + " $preview, " + android.name
103+
} else {
104+
getAndroidDessertPreview()
105+
}
106+
}
80107
if (MyApplication.instance.isGoEdition()) {
81-
myAndroidVersionName += " (Go)"
108+
myNameAndDessert += " (Go)"
109+
}
110+
111+
var mine = MyApplication.getMyString(R.string.android_info, myNameAndDessert, myApiFull)
112+
113+
var myExtension = EXTENSION_NONE
114+
if (isAtLeastStableAndroid11()) {
115+
myExtension = getSdkExtension(Build.VERSION.SDK_INT)
116+
mine += "\n" + MyApplication.getMyString(R.string.android_info_sdk_extension,myExtension)
82117
}
83-
val mine = MyApplication.getMyString(R.string.android_info, myAndroidVersionName, getAndroidApiLevel())
84118
// endregion [Mine]
85119

86-
// region [LatestStable]
87-
val stable = lld.android.stable
88-
val latestStable = MyApplication.getMyString(R.string.android_info, stable.version, stable.api)
89-
// endregion [LatestStable]
90-
91-
// region [LowestSupport]
92-
val support = lld.android.support
93-
val lowestSupport = MyApplication.getMyString(R.string.android_info, support.version, support.api)
94-
// endregion [LowestSupport]
95-
96-
// region [Beta]
97-
val lldStablePreview = lld.android.stablePreview
98-
val stablePreviewVersion = lldStablePreview.version
99-
val stablePreviewApi = lldStablePreview.api
100-
val stablePreview = MyApplication.getMyString(R.string.android_info, stablePreviewVersion, stablePreviewApi)
101-
// endregion [Beta]
102-
103-
// region [Canary]
104-
val lldPreview = lld.android.preview
105-
val previewVersion = lldPreview.version
106-
val previewApi = lldPreview.api
107-
val latestPreview = MyApplication.getMyString(R.string.android_info, previewVersion, previewApi)
108-
// endregion [Canary]
109-
110-
// region [LatestInternal]
111-
val internal = lld.android.internal
112-
val latestInternal = MyApplication.getMyString(R.string.android_info, internal.version, internal.api)
113-
// endregion [LatestInternal]
120+
fun oneLine(android: Lld.Androids.Android) =
121+
MyApplication.getMyString(R.string.android_info, android.version, android.apiFull)
122+
123+
val lldAndroid = lld.android
124+
125+
var latestStable = oneLine(lldAndroid.stable)
126+
if (isAtLeastStableAndroid11()) {
127+
latestStable += "\n" + MyApplication.getMyString(R.string.android_info_sdk_extension,lldAndroid.stable.extension) + "\n"
128+
}
129+
val lowestSupport = oneLine(lldAndroid.support)
130+
val stablePreview = oneLine(lldAndroid.stablePreview) // Beta
131+
val latestPreview = oneLine(lldAndroid.preview) // Canary
132+
val latestInternal = oneLine(lldAndroid.internal)
133+
134+
val infoDetailArgs = arrayOf(mine, latestStable, lowestSupport, stablePreview, latestPreview, latestInternal)
114135

115136
@AttrRes val color = when {
116-
isLatestStableAndroid(lld) || isLatestPreviewAndroid(lld) -> R.attr.colorNoProblem
137+
(isLatestStableAndroid(lld) || isLatestPreviewAndroid(lld)) && myExtension >= lldAndroid.stable.extension -> R.attr.colorNoProblem
117138
isSupportedByUpstreamAndroid(lld) -> R.attr.colorWaring
118139
else -> R.attr.colorCritical
119140
}
120141

121-
val infoDetailArgs = arrayOf(mine, latestStable, lowestSupport, stablePreview, latestPreview, latestInternal)
122142
return toColoredMyModel(
123143
MyApplication.getMyString(R.string.android_info_title),
124144
MyApplication.getMyString(R.string.android_info_detail, *infoDetailArgs),
@@ -1005,9 +1025,7 @@ class HomeRepository(
10051025
}
10061026
var systemApkList = installedApplications.filter {
10071027
val systemFlags = it.flags and (ApplicationInfo.FLAG_UPDATED_SYSTEM_APP or ApplicationInfo.FLAG_SYSTEM)
1008-
(systemFlags > 0) && (it.targetSdkVersion < Build.VERSION.SDK_INT
1009-
|| (isPreviewAndroid() && it.targetSdkVersion == Build.VERSION.SDK_INT)
1010-
)
1028+
(systemFlags > 0) && (it.targetSdkVersion < sdkInt)
10111029
}
10121030

10131031
var result = MyApplication.getMyString(

app/src/main/java/net/imknown/android/forefrontinfo/ui/home/res/values-fr-rFR/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
<string name="android_info_title">"Version d'Android"</string>
2020
<string name="android_info">%1$s (API %2$s)</string>
21+
<string name="android_info_preview">Aperçu</string>
22+
<string name="android_info_sdk_extension">Extension SDK: %1$s</string>
2123
<string name="android_info_detail">Moi: %1$s\n\nDernière stable: %2$s\nPlus faible prise en charge: %3$s\nDernière Béta: %4$s\nDernière aperçu: %5$s\nDernière interne: %6$s</string>
2224

2325
<string name="android_build_id_title">Id de build Android</string>

app/src/main/java/net/imknown/android/forefrontinfo/ui/home/res/values-zh-rCN/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
<string name="android_info_title">Android 版本</string>
2020
<string name="android_info">%1$s(API %2$s)</string>
21+
<string name="android_info_preview">预览</string>
22+
<string name="android_info_sdk_extension">SDK 扩展: %1$s</string>
2123
<string name="android_info_detail">我的:%1$s\n\n最新稳定:%2$s\n最低支持:%3$s\n最新 Beta:%4$s\n最新预览:%5$s\n最新内部:%6$s</string>
2224

2325
<string name="android_build_id_title">Android 构建 id</string>

app/src/main/java/net/imknown/android/forefrontinfo/ui/home/res/values-zh-rTW/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
<string name="android_info_title">Android 版本</string>
2020
<string name="android_info">%1$s(API %2$s)</string>
21+
<string name="android_info_preview">預覽</string>
22+
<string name="android_info_sdk_extension">SDK 擴充: %1$s</string>
2123
<string name="android_info_detail">我的:%1$s\n\n最新穩定:%2$s\n最低支援:%3$s\n最新 Beta:%4$s\n最新預覽:%5$s\n最新內部:%6$s</string>
2224

2325
<string name="android_build_id_title">Android 構建 ID</string>

app/src/main/java/net/imknown/android/forefrontinfo/ui/home/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
<string name="android_info_title">Android version</string>
2020
<string name="android_info">%1$s (API %2$s)</string>
21+
<string name="android_info_preview">Preview</string>
22+
<string name="android_info_sdk_extension">SDK Extension: %1$s</string>
2123
<string name="android_info_detail">Mine: %1$s\n\nLatest stable: %2$s\nLowest support: %3$s\nLatest Beta: %4$s\nLatest preview: %5$s\nLatest internal: %6$s</string>
2224

2325
<string name="android_build_id_title">Android build ids</string>

0 commit comments

Comments
 (0)