Add platform level

This commit is contained in:
Jonas Lochmann 2023-06-12 02:00:00 +02:00
parent a17d6d4fe3
commit 86d0592524
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
11 changed files with 1871 additions and 16 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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