mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Add platform level
This commit is contained in:
parent
a17d6d4fe3
commit
86d0592524
11 changed files with 1871 additions and 16 deletions
|
@ -23,7 +23,7 @@ apply plugin: 'com.squareup.wire'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'io.timelimit.android'
|
namespace 'io.timelimit.android'
|
||||||
compileSdkVersion 33
|
compileSdkVersion 34
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "io.timelimit.android"
|
applicationId "io.timelimit.android"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
|
|
1773
app/schemas/io.timelimit.android.data.RoomDatabase/47.json
Normal file
1773
app/schemas/io.timelimit.android.data.RoomDatabase/47.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -17,11 +17,11 @@ package io.timelimit.android.data
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import androidx.room.AutoMigration
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.InvalidationTracker
|
import androidx.room.InvalidationTracker
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import io.timelimit.android.async.Threads
|
import io.timelimit.android.async.Threads
|
||||||
import io.timelimit.android.data.dao.DerivedDataDao
|
import io.timelimit.android.data.dao.DerivedDataDao
|
||||||
|
@ -61,7 +61,9 @@ import java.util.concurrent.TimeUnit
|
||||||
UserU2FKey::class,
|
UserU2FKey::class,
|
||||||
WidgetCategory::class,
|
WidgetCategory::class,
|
||||||
WidgetConfig::class
|
WidgetConfig::class
|
||||||
], version = 46)
|
], version = 47, autoMigrations = [
|
||||||
|
AutoMigration(from = 46, to = 47)
|
||||||
|
])
|
||||||
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
||||||
companion object {
|
companion object {
|
||||||
private val lock = Object()
|
private val lock = Object()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -94,7 +94,11 @@ data class Device(
|
||||||
@ColumnInfo(name = "q_or_later")
|
@ColumnInfo(name = "q_or_later")
|
||||||
val qOrLater: Boolean,
|
val qOrLater: Boolean,
|
||||||
@ColumnInfo(name = "manipulation_flags")
|
@ColumnInfo(name = "manipulation_flags")
|
||||||
val manipulationFlags: Long
|
val manipulationFlags: Long,
|
||||||
|
@ColumnInfo(name = "platform_type")
|
||||||
|
val platformType: String?,
|
||||||
|
@ColumnInfo(name = "platform_level", defaultValue = "0")
|
||||||
|
val platformLevel: Int
|
||||||
): JsonSerializable {
|
): JsonSerializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val ID = "id"
|
private const val ID = "id"
|
||||||
|
@ -129,6 +133,8 @@ data class Device(
|
||||||
private const val ENABLE_ACTIVITY_LEVEL_BLOCKING = "ealb"
|
private const val ENABLE_ACTIVITY_LEVEL_BLOCKING = "ealb"
|
||||||
private const val Q_OR_LATER = "qol"
|
private const val Q_OR_LATER = "qol"
|
||||||
private const val MANIPULATION_FLAGS = "mf"
|
private const val MANIPULATION_FLAGS = "mf"
|
||||||
|
private const val PLATFORM_TYPE = "pt"
|
||||||
|
private const val PLATFORM_LEVEL = "pl"
|
||||||
|
|
||||||
fun parse(reader: JsonReader): Device {
|
fun parse(reader: JsonReader): Device {
|
||||||
var id: String? = null
|
var id: String? = null
|
||||||
|
@ -163,6 +169,8 @@ data class Device(
|
||||||
var enableActivityLevelBlocking = false
|
var enableActivityLevelBlocking = false
|
||||||
var qOrLater = false
|
var qOrLater = false
|
||||||
var manipulationFlags = 0L
|
var manipulationFlags = 0L
|
||||||
|
var platformType: String? = null
|
||||||
|
var platformLevel = 0
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
|
|
||||||
|
@ -200,6 +208,8 @@ data class Device(
|
||||||
ENABLE_ACTIVITY_LEVEL_BLOCKING -> enableActivityLevelBlocking = reader.nextBoolean()
|
ENABLE_ACTIVITY_LEVEL_BLOCKING -> enableActivityLevelBlocking = reader.nextBoolean()
|
||||||
Q_OR_LATER -> qOrLater = reader.nextBoolean()
|
Q_OR_LATER -> qOrLater = reader.nextBoolean()
|
||||||
MANIPULATION_FLAGS -> manipulationFlags = reader.nextLong()
|
MANIPULATION_FLAGS -> manipulationFlags = reader.nextLong()
|
||||||
|
PLATFORM_TYPE -> platformType = reader.nextString()
|
||||||
|
PLATFORM_LEVEL -> platformLevel = reader.nextInt()
|
||||||
else -> reader.skipValue()
|
else -> reader.skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,7 +248,9 @@ data class Device(
|
||||||
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled,
|
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled,
|
||||||
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
||||||
qOrLater = qOrLater,
|
qOrLater = qOrLater,
|
||||||
manipulationFlags = manipulationFlags
|
manipulationFlags = manipulationFlags,
|
||||||
|
platformType = platformType,
|
||||||
|
platformLevel = platformLevel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,6 +322,8 @@ data class Device(
|
||||||
writer.name(ENABLE_ACTIVITY_LEVEL_BLOCKING).value(enableActivityLevelBlocking)
|
writer.name(ENABLE_ACTIVITY_LEVEL_BLOCKING).value(enableActivityLevelBlocking)
|
||||||
writer.name(Q_OR_LATER).value(qOrLater)
|
writer.name(Q_OR_LATER).value(qOrLater)
|
||||||
writer.name(MANIPULATION_FLAGS).value(manipulationFlags)
|
writer.name(MANIPULATION_FLAGS).value(manipulationFlags)
|
||||||
|
platformType?.let { writer.name(PLATFORM_TYPE).value(it) }
|
||||||
|
writer.name(PLATFORM_LEVEL).value(platformLevel)
|
||||||
|
|
||||||
writer.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
|
@ -393,3 +407,7 @@ object HadManipulationFlag {
|
||||||
object ManipulationFlag {
|
object ManipulationFlag {
|
||||||
const val USED_FGS_KILLER = 1L shl 0
|
const val USED_FGS_KILLER = 1L shl 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object DevicePlatform {
|
||||||
|
const val ANDROID = "android"
|
||||||
|
}
|
|
@ -110,7 +110,9 @@ class AppSetupLogic(private val appLogic: AppLogic) {
|
||||||
wasAccessibilityServiceEnabled = false,
|
wasAccessibilityServiceEnabled = false,
|
||||||
enableActivityLevelBlocking = false,
|
enableActivityLevelBlocking = false,
|
||||||
qOrLater = AndroidVersion.qOrLater,
|
qOrLater = AndroidVersion.qOrLater,
|
||||||
manipulationFlags = 0
|
manipulationFlags = 0,
|
||||||
|
platformType = DevicePlatform.ANDROID,
|
||||||
|
platformLevel = AndroidVersion.platformLevel
|
||||||
)
|
)
|
||||||
|
|
||||||
appLogic.database.device().addDeviceSync(device)
|
appLogic.database.device().addDeviceSync(device)
|
||||||
|
|
|
@ -26,6 +26,7 @@ import io.timelimit.android.coroutines.executeAndWait
|
||||||
import io.timelimit.android.coroutines.runAsync
|
import io.timelimit.android.coroutines.runAsync
|
||||||
import io.timelimit.android.coroutines.runAsyncExpectForever
|
import io.timelimit.android.coroutines.runAsyncExpectForever
|
||||||
import io.timelimit.android.data.backup.DatabaseBackup
|
import io.timelimit.android.data.backup.DatabaseBackup
|
||||||
|
import io.timelimit.android.data.model.DevicePlatform
|
||||||
import io.timelimit.android.data.model.ExperimentalFlags
|
import io.timelimit.android.data.model.ExperimentalFlags
|
||||||
import io.timelimit.android.data.model.ManipulationFlag
|
import io.timelimit.android.data.model.ManipulationFlag
|
||||||
import io.timelimit.android.data.model.UserType
|
import io.timelimit.android.data.model.UserType
|
||||||
|
@ -982,6 +983,8 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
val overlayPermission = appLogic.platformIntegration.getDrawOverOtherAppsPermissionStatus(useStrictChecking)
|
val overlayPermission = appLogic.platformIntegration.getDrawOverOtherAppsPermissionStatus(useStrictChecking)
|
||||||
val accessibilityService = appLogic.platformIntegration.isAccessibilityServiceEnabled()
|
val accessibilityService = appLogic.platformIntegration.isAccessibilityServiceEnabled()
|
||||||
val qOrLater = AndroidVersion.qOrLater
|
val qOrLater = AndroidVersion.qOrLater
|
||||||
|
val platformType = DevicePlatform.ANDROID
|
||||||
|
val platformLevel = AndroidVersion.platformLevel
|
||||||
|
|
||||||
if (protectionLevel != deviceEntry.currentProtectionLevel) {
|
if (protectionLevel != deviceEntry.currentProtectionLevel) {
|
||||||
changes = changes.copy(
|
changes = changes.copy(
|
||||||
|
@ -1020,6 +1023,14 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
if (qOrLater && !deviceEntry.qOrLater) {
|
if (qOrLater && !deviceEntry.qOrLater) {
|
||||||
changes = changes.copy(isQOrLaterNow = true)
|
changes = changes.copy(isQOrLaterNow = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deviceEntry.platformType != platformType) {
|
||||||
|
changes = changes.copy(newPlatformType = platformType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceEntry.platformLevel != platformLevel) {
|
||||||
|
changes = changes.copy(newPlatformLevel = platformLevel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return changes
|
return changes
|
||||||
|
|
|
@ -194,7 +194,9 @@ object ApplyServerDataStatus {
|
||||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
||||||
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
||||||
qOrLater = newDevice.qOrLater,
|
qOrLater = newDevice.qOrLater,
|
||||||
manipulationFlags = newDevice.manipulationFlags
|
manipulationFlags = newDevice.manipulationFlags,
|
||||||
|
platformType = newDevice.platformType,
|
||||||
|
platformLevel = newDevice.platformLevel ?: 0
|
||||||
))
|
))
|
||||||
|
|
||||||
newDeviceTitles.add(newDevice.name)
|
newDeviceTitles.add(newDevice.name)
|
||||||
|
@ -231,7 +233,9 @@ object ApplyServerDataStatus {
|
||||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
||||||
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
||||||
qOrLater = newDevice.qOrLater,
|
qOrLater = newDevice.qOrLater,
|
||||||
manipulationFlags = newDevice.manipulationFlags
|
manipulationFlags = newDevice.manipulationFlags,
|
||||||
|
platformType = newDevice.platformType ?: oldDeviceEntry.platformType,
|
||||||
|
platformLevel = newDevice.platformLevel ?: oldDeviceEntry.platformLevel
|
||||||
)
|
)
|
||||||
|
|
||||||
if (updatedDeviceEntry != oldDeviceEntry) {
|
if (updatedDeviceEntry != oldDeviceEntry) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -1220,7 +1220,9 @@ data class UpdateDeviceStatusAction(
|
||||||
val newAppVersion: Int?,
|
val newAppVersion: Int?,
|
||||||
val didReboot: Boolean,
|
val didReboot: Boolean,
|
||||||
val isQOrLaterNow: Boolean,
|
val isQOrLaterNow: Boolean,
|
||||||
val addedManipulationFlags: Long
|
val addedManipulationFlags: Long,
|
||||||
|
val newPlatformType: String?,
|
||||||
|
val newPlatformLevel: Int?
|
||||||
): AppLogicAction() {
|
): AppLogicAction() {
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE_VALUE = "UPDATE_DEVICE_STATUS"
|
const val TYPE_VALUE = "UPDATE_DEVICE_STATUS"
|
||||||
|
@ -1233,6 +1235,8 @@ data class UpdateDeviceStatusAction(
|
||||||
private const val DID_REBOOT = "didReboot"
|
private const val DID_REBOOT = "didReboot"
|
||||||
private const val IS_Q_OR_LATER_NOW = "isQOrLaterNow"
|
private const val IS_Q_OR_LATER_NOW = "isQOrLaterNow"
|
||||||
private const val ADDED_MANIPULATION_FLAGS = "addedManipulationFlags"
|
private const val ADDED_MANIPULATION_FLAGS = "addedManipulationFlags"
|
||||||
|
private const val PLATFORM_TYPE = "platformType"
|
||||||
|
private const val PLATFORM_LEVEL = "platformLevel"
|
||||||
|
|
||||||
val empty = UpdateDeviceStatusAction(
|
val empty = UpdateDeviceStatusAction(
|
||||||
newProtectionLevel = null,
|
newProtectionLevel = null,
|
||||||
|
@ -1243,7 +1247,9 @@ data class UpdateDeviceStatusAction(
|
||||||
newAppVersion = null,
|
newAppVersion = null,
|
||||||
didReboot = false,
|
didReboot = false,
|
||||||
isQOrLaterNow = false,
|
isQOrLaterNow = false,
|
||||||
addedManipulationFlags = 0L
|
addedManipulationFlags = 0L,
|
||||||
|
newPlatformType = null,
|
||||||
|
newPlatformLevel = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1251,6 +1257,14 @@ data class UpdateDeviceStatusAction(
|
||||||
if (newAppVersion != null && newAppVersion < 0) {
|
if (newAppVersion != null && newAppVersion < 0) {
|
||||||
throw IllegalArgumentException()
|
throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newPlatformType != null && newPlatformType.isEmpty()) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPlatformLevel != null && newPlatformLevel < 0) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(writer: JsonWriter) {
|
override fun serialize(writer: JsonWriter) {
|
||||||
|
@ -1304,6 +1318,14 @@ data class UpdateDeviceStatusAction(
|
||||||
writer.name(ADDED_MANIPULATION_FLAGS).value(addedManipulationFlags)
|
writer.name(ADDED_MANIPULATION_FLAGS).value(addedManipulationFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newPlatformType != null) {
|
||||||
|
writer.name(PLATFORM_TYPE).value(newPlatformType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPlatformLevel != null) {
|
||||||
|
writer.name(PLATFORM_LEVEL).value(newPlatformLevel)
|
||||||
|
}
|
||||||
|
|
||||||
writer.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -305,6 +305,14 @@ object LocalDatabaseAppLogicActionDispatcher {
|
||||||
device = device.copy(qOrLater = true)
|
device = device.copy(qOrLater = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.newPlatformType != null) {
|
||||||
|
device = device.copy(platformType = action.newPlatformType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.newPlatformLevel != null) {
|
||||||
|
device = device.copy(platformLevel = action.newPlatformLevel)
|
||||||
|
}
|
||||||
|
|
||||||
if (action.addedManipulationFlags != 0L) {
|
if (action.addedManipulationFlags != 0L) {
|
||||||
device = device.copy(manipulationFlags = device.manipulationFlags or action.addedManipulationFlags)
|
device = device.copy(manipulationFlags = device.manipulationFlags or action.addedManipulationFlags)
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,7 +323,9 @@ data class ServerDeviceData(
|
||||||
val enableActivityLevelBlocking: Boolean,
|
val enableActivityLevelBlocking: Boolean,
|
||||||
val qOrLater: Boolean,
|
val qOrLater: Boolean,
|
||||||
val manipulationFlags: Long,
|
val manipulationFlags: Long,
|
||||||
val publicKey: ByteArray?
|
val publicKey: ByteArray?,
|
||||||
|
val platformType: String?,
|
||||||
|
val platformLevel: Int?
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEVICE_ID = "deviceId"
|
private const val DEVICE_ID = "deviceId"
|
||||||
|
@ -358,6 +360,8 @@ data class ServerDeviceData(
|
||||||
private const val Q_OR_LATER = "qOrLater"
|
private const val Q_OR_LATER = "qOrLater"
|
||||||
private const val MANIPULATION_FLAGS = "mFlags"
|
private const val MANIPULATION_FLAGS = "mFlags"
|
||||||
private const val PUBLIC_KEY = "pk"
|
private const val PUBLIC_KEY = "pk"
|
||||||
|
private const val PLATFORM_TYPE = "pType"
|
||||||
|
private const val PLATFORM_LEVEL = "pLevel"
|
||||||
|
|
||||||
fun parse(reader: JsonReader): ServerDeviceData {
|
fun parse(reader: JsonReader): ServerDeviceData {
|
||||||
var deviceId: String? = null
|
var deviceId: String? = null
|
||||||
|
@ -392,6 +396,8 @@ data class ServerDeviceData(
|
||||||
var qOrLater = false
|
var qOrLater = false
|
||||||
var manipulationFlags = 0L
|
var manipulationFlags = 0L
|
||||||
var publicKey: ByteArray? = null
|
var publicKey: ByteArray? = null
|
||||||
|
var platformType: String? = null
|
||||||
|
var platformLevel: Int? = null
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
|
@ -428,6 +434,8 @@ data class ServerDeviceData(
|
||||||
Q_OR_LATER -> qOrLater = reader.nextBoolean()
|
Q_OR_LATER -> qOrLater = reader.nextBoolean()
|
||||||
MANIPULATION_FLAGS -> manipulationFlags = reader.nextLong()
|
MANIPULATION_FLAGS -> manipulationFlags = reader.nextLong()
|
||||||
PUBLIC_KEY -> publicKey = reader.nextString().parseBase64()
|
PUBLIC_KEY -> publicKey = reader.nextString().parseBase64()
|
||||||
|
PLATFORM_TYPE -> platformType = reader.nextString()
|
||||||
|
PLATFORM_LEVEL -> platformLevel = reader.nextInt()
|
||||||
else -> reader.skipValue()
|
else -> reader.skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -465,7 +473,9 @@ data class ServerDeviceData(
|
||||||
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
||||||
qOrLater = qOrLater,
|
qOrLater = qOrLater,
|
||||||
manipulationFlags = manipulationFlags,
|
manipulationFlags = manipulationFlags,
|
||||||
publicKey = publicKey
|
publicKey = publicKey,
|
||||||
|
platformType = platformType,
|
||||||
|
platformLevel = platformLevel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,4 +19,9 @@ import android.os.Build
|
||||||
|
|
||||||
object AndroidVersion {
|
object AndroidVersion {
|
||||||
val qOrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
val qOrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
||||||
|
|
||||||
|
val platformLevel =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 2
|
||||||
|
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) 1
|
||||||
|
else 0
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue