mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Add FGS task manager manipulation type
This commit is contained in:
parent
5f61efbd14
commit
7021a9c699
19 changed files with 1461 additions and 82 deletions
1270
app/schemas/io.timelimit.android.data.RoomDatabase/42.json
Normal file
1270
app/schemas/io.timelimit.android.data.RoomDatabase/42.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -293,6 +293,12 @@ object DatabaseMigrations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val MIGRATE_TO_V42 = object: Migration(41, 42) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE device ADD COLUMN manipulation_flags INTEGER NOT NULL DEFAULT 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val ALL = arrayOf(
|
val ALL = arrayOf(
|
||||||
MIGRATE_TO_V2,
|
MIGRATE_TO_V2,
|
||||||
MIGRATE_TO_V3,
|
MIGRATE_TO_V3,
|
||||||
|
@ -333,6 +339,7 @@ object DatabaseMigrations {
|
||||||
MIGRATE_TO_V38,
|
MIGRATE_TO_V38,
|
||||||
MIGRATE_TO_V39,
|
MIGRATE_TO_V39,
|
||||||
MIGRATE_TO_V40,
|
MIGRATE_TO_V40,
|
||||||
MIGRATE_TO_V41
|
MIGRATE_TO_V41,
|
||||||
|
MIGRATE_TO_V42
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ import java.util.concurrent.TimeUnit
|
||||||
CategoryNetworkId::class,
|
CategoryNetworkId::class,
|
||||||
ChildTask::class,
|
ChildTask::class,
|
||||||
CategoryTimeWarning::class
|
CategoryTimeWarning::class
|
||||||
], version = 41)
|
], version = 42)
|
||||||
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 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 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
|
||||||
|
@ -92,7 +92,9 @@ data class Device(
|
||||||
@ColumnInfo(name = "enable_activity_level_blocking")
|
@ColumnInfo(name = "enable_activity_level_blocking")
|
||||||
val enableActivityLevelBlocking: Boolean,
|
val enableActivityLevelBlocking: Boolean,
|
||||||
@ColumnInfo(name = "q_or_later")
|
@ColumnInfo(name = "q_or_later")
|
||||||
val qOrLater: Boolean
|
val qOrLater: Boolean,
|
||||||
|
@ColumnInfo(name = "manipulation_flags")
|
||||||
|
val manipulationFlags: Long
|
||||||
): JsonSerializable {
|
): JsonSerializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val ID = "id"
|
private const val ID = "id"
|
||||||
|
@ -126,6 +128,7 @@ data class Device(
|
||||||
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wase"
|
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wase"
|
||||||
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"
|
||||||
|
|
||||||
fun parse(reader: JsonReader): Device {
|
fun parse(reader: JsonReader): Device {
|
||||||
var id: String? = null
|
var id: String? = null
|
||||||
|
@ -159,6 +162,7 @@ data class Device(
|
||||||
var wasAccessibilityServiceEnabled = false
|
var wasAccessibilityServiceEnabled = false
|
||||||
var enableActivityLevelBlocking = false
|
var enableActivityLevelBlocking = false
|
||||||
var qOrLater = false
|
var qOrLater = false
|
||||||
|
var manipulationFlags = 0L
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
|
|
||||||
|
@ -195,6 +199,7 @@ data class Device(
|
||||||
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
||||||
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()
|
||||||
else -> reader.skipValue()
|
else -> reader.skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +237,8 @@ data class Device(
|
||||||
accessibilityServiceEnabled = accessibilityServiceEnabled,
|
accessibilityServiceEnabled = accessibilityServiceEnabled,
|
||||||
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled,
|
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled,
|
||||||
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
||||||
qOrLater = qOrLater
|
qOrLater = qOrLater,
|
||||||
|
manipulationFlags = manipulationFlags
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,6 +309,7 @@ data class Device(
|
||||||
writer.name(WAS_ACCESSIBILITY_SERVICE_ENABLED).value(wasAccessibilityServiceEnabled)
|
writer.name(WAS_ACCESSIBILITY_SERVICE_ENABLED).value(wasAccessibilityServiceEnabled)
|
||||||
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.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
|
@ -331,7 +338,7 @@ data class Device(
|
||||||
manipulationOfAccessibilityService
|
manipulationOfAccessibilityService
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
val hasAnyManipulation = hasActiveManipulationWarning || hadManipulation
|
val hasAnyManipulation = hasActiveManipulationWarning || hadManipulation || manipulationFlags != 0L
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
val missingPermissionAtQOrLater = qOrLater &&
|
val missingPermissionAtQOrLater = qOrLater &&
|
||||||
|
@ -382,3 +389,7 @@ object HadManipulationFlag {
|
||||||
const val OVERLAY_PERMISSION = 1L shl 4
|
const val OVERLAY_PERMISSION = 1L shl 4
|
||||||
const val ACCESSIBILITY_SERVICE = 1L shl 5
|
const val ACCESSIBILITY_SERVICE = 1L shl 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ManipulationFlag {
|
||||||
|
const val USED_FGS_KILLER = 1L shl 0
|
||||||
|
}
|
|
@ -89,7 +89,7 @@ abstract class PlatformIntegration(
|
||||||
confirmationLevel: SystemPermissionConfirmationLevel = SystemPermissionConfirmationLevel.None
|
confirmationLevel: SystemPermissionConfirmationLevel = SystemPermissionConfirmationLevel.None
|
||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
abstract fun getExitLog(): List<ExitLogItem>
|
abstract fun getExitLog(length: Int): List<ExitLogItem>
|
||||||
|
|
||||||
var installedAppsChangeListener: Runnable? = null
|
var installedAppsChangeListener: Runnable? = null
|
||||||
var systemClockChangeListener: Runnable? = null
|
var systemClockChangeListener: Runnable? = null
|
||||||
|
|
|
@ -815,9 +815,9 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExitLog(): List<ExitLogItem> {
|
override fun getExitLog(length: Int): List<ExitLogItem> {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
activityManager.getHistoricalProcessExitReasons(context.packageName, 0, 0)
|
activityManager.getHistoricalProcessExitReasons(context.packageName, 0, length)
|
||||||
.map { ExitLogItem.fromApplicationExitInfo(it) }
|
.map { ExitLogItem.fromApplicationExitInfo(it) }
|
||||||
} else emptyList()
|
} else emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,5 +190,5 @@ class DummyIntegration(
|
||||||
confirmationLevel: SystemPermissionConfirmationLevel
|
confirmationLevel: SystemPermissionConfirmationLevel
|
||||||
): Boolean = false
|
): Boolean = false
|
||||||
|
|
||||||
override fun getExitLog(): List<ExitLogItem> = emptyList()
|
override fun getExitLog(length: Int): List<ExitLogItem> = emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,8 @@ class AppSetupLogic(private val appLogic: AppLogic) {
|
||||||
accessibilityServiceEnabled = false,
|
accessibilityServiceEnabled = false,
|
||||||
wasAccessibilityServiceEnabled = false,
|
wasAccessibilityServiceEnabled = false,
|
||||||
enableActivityLevelBlocking = false,
|
enableActivityLevelBlocking = false,
|
||||||
qOrLater = AndroidVersion.qOrLater
|
qOrLater = AndroidVersion.qOrLater,
|
||||||
|
manipulationFlags = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
appLogic.database.device().addDeviceSync(device)
|
appLogic.database.device().addDeviceSync(device)
|
||||||
|
|
|
@ -26,16 +26,14 @@ 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.ExperimentalFlags
|
import io.timelimit.android.data.model.ExperimentalFlags
|
||||||
|
import io.timelimit.android.data.model.ManipulationFlag
|
||||||
import io.timelimit.android.data.model.UserType
|
import io.timelimit.android.data.model.UserType
|
||||||
import io.timelimit.android.data.model.derived.UserRelatedData
|
import io.timelimit.android.data.model.derived.UserRelatedData
|
||||||
import io.timelimit.android.date.DateInTimezone
|
import io.timelimit.android.date.DateInTimezone
|
||||||
import io.timelimit.android.date.getMinuteOfWeek
|
import io.timelimit.android.date.getMinuteOfWeek
|
||||||
import io.timelimit.android.extensions.MinuteOfDay
|
import io.timelimit.android.extensions.MinuteOfDay
|
||||||
import io.timelimit.android.extensions.nextBlockedMinuteOfWeek
|
import io.timelimit.android.extensions.nextBlockedMinuteOfWeek
|
||||||
import io.timelimit.android.integration.platform.AppStatusMessage
|
import io.timelimit.android.integration.platform.*
|
||||||
import io.timelimit.android.integration.platform.ForegroundApp
|
|
||||||
import io.timelimit.android.integration.platform.NetworkId
|
|
||||||
import io.timelimit.android.integration.platform.ProtectionLevel
|
|
||||||
import io.timelimit.android.integration.platform.android.AccessibilityService
|
import io.timelimit.android.integration.platform.android.AccessibilityService
|
||||||
import io.timelimit.android.livedata.*
|
import io.timelimit.android.livedata.*
|
||||||
import io.timelimit.android.logic.blockingreason.AppBaseHandling
|
import io.timelimit.android.logic.blockingreason.AppBaseHandling
|
||||||
|
@ -76,6 +74,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
runAsyncExpectForever { syncDeviceStatusLoop() }
|
runAsyncExpectForever { syncDeviceStatusLoop() }
|
||||||
runAsyncExpectForever { backupDatabaseLoop() }
|
runAsyncExpectForever { backupDatabaseLoop() }
|
||||||
runAsyncExpectForever { annoyUserOnManipulationLoop() }
|
runAsyncExpectForever { annoyUserOnManipulationLoop() }
|
||||||
|
runAsync { checkForceKilled() }
|
||||||
runAsync {
|
runAsync {
|
||||||
// this is effective after an reboot
|
// this is effective after an reboot
|
||||||
|
|
||||||
|
@ -924,6 +923,33 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun checkForceKilled() {
|
||||||
|
appLogic.platformIntegration.getExitLog(1).singleOrNull()?.let { item ->
|
||||||
|
if (
|
||||||
|
item.reason == ExitReason.UserRequest &&
|
||||||
|
item.description != null &&
|
||||||
|
item.description.startsWith("fully stop ") &&
|
||||||
|
item.description.endsWith("by user request")
|
||||||
|
) {
|
||||||
|
appLogic.isInitialized.waitUntilValueMatches { it == true }
|
||||||
|
|
||||||
|
try {
|
||||||
|
ApplyActionUtil.applyAppLogicAction(
|
||||||
|
action = UpdateDeviceStatusAction.empty.copy(
|
||||||
|
addedManipulationFlags = ManipulationFlag.USED_FGS_KILLER
|
||||||
|
),
|
||||||
|
appLogic = appLogic,
|
||||||
|
ignoreIfDeviceIsNotConfigured = true
|
||||||
|
)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.w(LOG_TAG, "could not save a forced kill notification", ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val syncDeviceStatusLock = Mutex()
|
private val syncDeviceStatusLock = Mutex()
|
||||||
|
|
||||||
fun reportDeviceReboot() {
|
fun reportDeviceReboot() {
|
||||||
|
|
|
@ -188,7 +188,8 @@ object ApplyServerDataStatus {
|
||||||
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
||||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
||||||
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
||||||
qOrLater = newDevice.qOrLater
|
qOrLater = newDevice.qOrLater,
|
||||||
|
manipulationFlags = newDevice.manipulationFlags
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// eventually update old entry
|
// eventually update old entry
|
||||||
|
@ -222,7 +223,8 @@ object ApplyServerDataStatus {
|
||||||
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
||||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
||||||
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
||||||
qOrLater = newDevice.qOrLater
|
qOrLater = newDevice.qOrLater,
|
||||||
|
manipulationFlags = newDevice.manipulationFlags
|
||||||
)
|
)
|
||||||
|
|
||||||
if (updatedDeviceEntry != oldDeviceEntry) {
|
if (updatedDeviceEntry != oldDeviceEntry) {
|
||||||
|
|
|
@ -1081,7 +1081,8 @@ data class UpdateDeviceStatusAction(
|
||||||
val newAccessibilityServiceEnabled: Boolean?,
|
val newAccessibilityServiceEnabled: Boolean?,
|
||||||
val newAppVersion: Int?,
|
val newAppVersion: Int?,
|
||||||
val didReboot: Boolean,
|
val didReboot: Boolean,
|
||||||
val isQOrLaterNow: Boolean
|
val isQOrLaterNow: Boolean,
|
||||||
|
val addedManipulationFlags: Long
|
||||||
): AppLogicAction() {
|
): AppLogicAction() {
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE_VALUE = "UPDATE_DEVICE_STATUS"
|
const val TYPE_VALUE = "UPDATE_DEVICE_STATUS"
|
||||||
|
@ -1093,6 +1094,7 @@ data class UpdateDeviceStatusAction(
|
||||||
private const val NEW_APP_VERSION = "appVersion"
|
private const val NEW_APP_VERSION = "appVersion"
|
||||||
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"
|
||||||
|
|
||||||
val empty = UpdateDeviceStatusAction(
|
val empty = UpdateDeviceStatusAction(
|
||||||
newProtectionLevel = null,
|
newProtectionLevel = null,
|
||||||
|
@ -1102,7 +1104,8 @@ data class UpdateDeviceStatusAction(
|
||||||
newAccessibilityServiceEnabled = null,
|
newAccessibilityServiceEnabled = null,
|
||||||
newAppVersion = null,
|
newAppVersion = null,
|
||||||
didReboot = false,
|
didReboot = false,
|
||||||
isQOrLaterNow = false
|
isQOrLaterNow = false,
|
||||||
|
addedManipulationFlags = 0L
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1159,6 +1162,10 @@ data class UpdateDeviceStatusAction(
|
||||||
writer.name(IS_Q_OR_LATER_NOW).value(true)
|
writer.name(IS_Q_OR_LATER_NOW).value(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addedManipulationFlags != 0L) {
|
||||||
|
writer.name(ADDED_MANIPULATION_FLAGS).value(addedManipulationFlags)
|
||||||
|
}
|
||||||
|
|
||||||
writer.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1174,7 +1181,8 @@ data class IgnoreManipulationAction(
|
||||||
val ignoreAccessibilityServiceManipulation: Boolean,
|
val ignoreAccessibilityServiceManipulation: Boolean,
|
||||||
val ignoreReboot: Boolean,
|
val ignoreReboot: Boolean,
|
||||||
val ignoreHadManipulation: Boolean,
|
val ignoreHadManipulation: Boolean,
|
||||||
val ignoreHadManipulationFlags: Long
|
val ignoreHadManipulationFlags: Long,
|
||||||
|
val ignoreManipulationFlags: Long
|
||||||
): ParentAction() {
|
): ParentAction() {
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE_VALUE = "IGNORE_MANIPULATION"
|
const val TYPE_VALUE = "IGNORE_MANIPULATION"
|
||||||
|
@ -1189,6 +1197,7 @@ data class IgnoreManipulationAction(
|
||||||
private const val IGNORE_HAD_MANIPULATION = "hadManipulation"
|
private const val IGNORE_HAD_MANIPULATION = "hadManipulation"
|
||||||
private const val IGNORE_REBOOT = "reboot"
|
private const val IGNORE_REBOOT = "reboot"
|
||||||
private const val IGNORE_HAD_MANIPULATION_FLAGS = "ignoreHadManipulationFlags"
|
private const val IGNORE_HAD_MANIPULATION_FLAGS = "ignoreHadManipulationFlags"
|
||||||
|
private const val IGNORE_MANIPULATION_FLAGS = "ignoreManipulationFlags"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -1204,7 +1213,8 @@ data class IgnoreManipulationAction(
|
||||||
(!ignoreAccessibilityServiceManipulation) &&
|
(!ignoreAccessibilityServiceManipulation) &&
|
||||||
(!ignoreReboot) &&
|
(!ignoreReboot) &&
|
||||||
(!ignoreHadManipulation) &&
|
(!ignoreHadManipulation) &&
|
||||||
(ignoreHadManipulationFlags == 0L)
|
(ignoreHadManipulationFlags == 0L) &&
|
||||||
|
(ignoreManipulationFlags == 0L)
|
||||||
|
|
||||||
override fun serialize(writer: JsonWriter) {
|
override fun serialize(writer: JsonWriter) {
|
||||||
writer.beginObject()
|
writer.beginObject()
|
||||||
|
@ -1222,6 +1232,8 @@ data class IgnoreManipulationAction(
|
||||||
writer.name(IGNORE_REBOOT).value(ignoreReboot)
|
writer.name(IGNORE_REBOOT).value(ignoreReboot)
|
||||||
writer.name(IGNORE_HAD_MANIPULATION_FLAGS).value(ignoreHadManipulationFlags)
|
writer.name(IGNORE_HAD_MANIPULATION_FLAGS).value(ignoreHadManipulationFlags)
|
||||||
|
|
||||||
|
if (ignoreManipulationFlags != 0L) writer.name(IGNORE_MANIPULATION_FLAGS).value(ignoreManipulationFlags)
|
||||||
|
|
||||||
writer.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,10 @@ object LocalDatabaseAppLogicActionDispatcher {
|
||||||
device = device.copy(qOrLater = true)
|
device = device.copy(qOrLater = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.addedManipulationFlags != 0L) {
|
||||||
|
device = device.copy(manipulationFlags = device.manipulationFlags or action.addedManipulationFlags)
|
||||||
|
}
|
||||||
|
|
||||||
database.device().updateDeviceEntry(device)
|
database.device().updateDeviceEntry(device)
|
||||||
|
|
||||||
null
|
null
|
||||||
|
|
|
@ -465,6 +465,12 @@ object LocalDatabaseParentActionDispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.ignoreManipulationFlags != 0L) {
|
||||||
|
deviceEntry = deviceEntry.copy(
|
||||||
|
manipulationFlags = deviceEntry.manipulationFlags and (action.ignoreManipulationFlags.inv())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
database.device().updateDeviceEntry(deviceEntry)
|
database.device().updateDeviceEntry(deviceEntry)
|
||||||
}
|
}
|
||||||
is SetKeepSignedInAction -> {
|
is SetKeepSignedInAction -> {
|
||||||
|
|
|
@ -298,7 +298,8 @@ data class ServerDeviceData(
|
||||||
val accessibilityServiceEnabled: Boolean,
|
val accessibilityServiceEnabled: Boolean,
|
||||||
val wasAccessibilityServiceEnabled: Boolean,
|
val wasAccessibilityServiceEnabled: Boolean,
|
||||||
val enableActivityLevelBlocking: Boolean,
|
val enableActivityLevelBlocking: Boolean,
|
||||||
val qOrLater: Boolean
|
val qOrLater: Boolean,
|
||||||
|
val manipulationFlags: Long
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEVICE_ID = "deviceId"
|
private const val DEVICE_ID = "deviceId"
|
||||||
|
@ -331,6 +332,7 @@ data class ServerDeviceData(
|
||||||
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wasAsEnabled"
|
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wasAsEnabled"
|
||||||
private const val ENABLE_ACTIVITY_LEVEL_BLOCKING = "activityLevelBlocking"
|
private const val ENABLE_ACTIVITY_LEVEL_BLOCKING = "activityLevelBlocking"
|
||||||
private const val Q_OR_LATER = "qOrLater"
|
private const val Q_OR_LATER = "qOrLater"
|
||||||
|
private const val MANIPULATION_FLAGS = "mFlags"
|
||||||
|
|
||||||
fun parse(reader: JsonReader): ServerDeviceData {
|
fun parse(reader: JsonReader): ServerDeviceData {
|
||||||
var deviceId: String? = null
|
var deviceId: String? = null
|
||||||
|
@ -363,6 +365,7 @@ data class ServerDeviceData(
|
||||||
var wasAccessibilityServiceEnabled: Boolean? = null
|
var wasAccessibilityServiceEnabled: Boolean? = null
|
||||||
var enableActivityLevelBlocking = false
|
var enableActivityLevelBlocking = false
|
||||||
var qOrLater = false
|
var qOrLater = false
|
||||||
|
var manipulationFlags = 0L
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
|
@ -397,6 +400,7 @@ data class ServerDeviceData(
|
||||||
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
||||||
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()
|
||||||
else -> reader.skipValue()
|
else -> reader.skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,7 +436,8 @@ data class ServerDeviceData(
|
||||||
accessibilityServiceEnabled = accessibilityServiceEnabled!!,
|
accessibilityServiceEnabled = accessibilityServiceEnabled!!,
|
||||||
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled!!,
|
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled!!,
|
||||||
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
||||||
qOrLater = qOrLater
|
qOrLater = qOrLater,
|
||||||
|
manipulationFlags = manipulationFlags
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import io.timelimit.android.ui.main.FragmentWithCustomTitle
|
||||||
class DiagnoseExitReasonFragment: Fragment(), FragmentWithCustomTitle {
|
class DiagnoseExitReasonFragment: Fragment(), FragmentWithCustomTitle {
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
val binding = DiagnoseExitReasonFragmentBinding.inflate(inflater, container, false)
|
val binding = DiagnoseExitReasonFragmentBinding.inflate(inflater, container, false)
|
||||||
val data = DefaultAppLogic.with(requireContext()).platformIntegration.getExitLog()
|
val data = DefaultAppLogic.with(requireContext()).platformIntegration.getExitLog(0)
|
||||||
val recycler = binding.recycler
|
val recycler = binding.recycler
|
||||||
val adapter = DiagnoseExitReasonAdapter()
|
val adapter = DiagnoseExitReasonAdapter()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 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
|
||||||
|
@ -25,6 +25,7 @@ import com.google.android.material.snackbar.Snackbar
|
||||||
import io.timelimit.android.R
|
import io.timelimit.android.R
|
||||||
import io.timelimit.android.data.model.Device
|
import io.timelimit.android.data.model.Device
|
||||||
import io.timelimit.android.data.model.HadManipulationFlag
|
import io.timelimit.android.data.model.HadManipulationFlag
|
||||||
|
import io.timelimit.android.data.model.ManipulationFlag
|
||||||
import io.timelimit.android.databinding.ManageDeviceManipulationViewBinding
|
import io.timelimit.android.databinding.ManageDeviceManipulationViewBinding
|
||||||
import io.timelimit.android.livedata.map
|
import io.timelimit.android.livedata.map
|
||||||
import io.timelimit.android.sync.actions.IgnoreManipulationAction
|
import io.timelimit.android.sync.actions.IgnoreManipulationAction
|
||||||
|
@ -62,7 +63,7 @@ object ManageDeviceManipulation {
|
||||||
entries.forEach { warning ->
|
entries.forEach { warning ->
|
||||||
container.addView(
|
container.addView(
|
||||||
createCheckbox().apply {
|
createCheckbox().apply {
|
||||||
setText(ManipulationWarningTypeLabel.getLabel(warning))
|
setText(warning.labelResourceId)
|
||||||
isChecked = selection.contains(warning)
|
isChecked = selection.contains(warning)
|
||||||
|
|
||||||
setOnCheckedChangeListener { _, newIsChecked ->
|
setOnCheckedChangeListener { _, newIsChecked ->
|
||||||
|
@ -128,66 +129,80 @@ data class ManipulationWarnings(val current: List<ManipulationWarningType>, val
|
||||||
fun isFlagSet(flag: Long) = (manipulationFlags and flag) == flag
|
fun isFlagSet(flag: Long) = (manipulationFlags and flag) == flag
|
||||||
|
|
||||||
if (device.manipulationTriedDisablingDeviceAdmin) {
|
if (device.manipulationTriedDisablingDeviceAdmin) {
|
||||||
current.add(ManipulationWarningType.TriedDisablingDeviceAdmin)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.TriedDisablingDeviceAdmin))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.manipulationOfAppVersion) {
|
if (device.manipulationOfAppVersion) {
|
||||||
current.add(ManipulationWarningType.AppDowngrade)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AppDowngrade))
|
||||||
}
|
}
|
||||||
if (isFlagSet(HadManipulationFlag.APP_VERSION)) {
|
if (isFlagSet(HadManipulationFlag.APP_VERSION)) {
|
||||||
past.add(ManipulationWarningType.AppDowngrade)
|
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AppDowngrade))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.manipulationOfProtectionLevel) {
|
if (device.manipulationOfProtectionLevel) {
|
||||||
current.add(ManipulationWarningType.DeviceAdmin)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.DeviceAdmin))
|
||||||
}
|
}
|
||||||
if (isFlagSet(HadManipulationFlag.PROTECTION_LEVEL)) {
|
if (isFlagSet(HadManipulationFlag.PROTECTION_LEVEL)) {
|
||||||
past.add(ManipulationWarningType.DeviceAdmin)
|
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.DeviceAdmin))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.manipulationOfUsageStats) {
|
if (device.manipulationOfUsageStats) {
|
||||||
current.add(ManipulationWarningType.UsageStats)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.UsageStats))
|
||||||
}
|
}
|
||||||
if (isFlagSet(HadManipulationFlag.USAGE_STATS_ACCESS)) {
|
if (isFlagSet(HadManipulationFlag.USAGE_STATS_ACCESS)) {
|
||||||
past.add(ManipulationWarningType.UsageStats)
|
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.UsageStats))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.manipulationOfNotificationAccess) {
|
if (device.manipulationOfNotificationAccess) {
|
||||||
current.add(ManipulationWarningType.NotificationAccess)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.NotificationAccess))
|
||||||
}
|
}
|
||||||
if (isFlagSet(HadManipulationFlag.NOTIFICATION_ACCESS)) {
|
if (isFlagSet(HadManipulationFlag.NOTIFICATION_ACCESS)) {
|
||||||
past.add(ManipulationWarningType.NotificationAccess)
|
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.NotificationAccess))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.manipulationOfOverlayPermission) {
|
if (device.manipulationOfOverlayPermission) {
|
||||||
current.add(ManipulationWarningType.OverlayPermission)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.OverlayPermission))
|
||||||
}
|
}
|
||||||
if (isFlagSet(HadManipulationFlag.OVERLAY_PERMISSION)) {
|
if (isFlagSet(HadManipulationFlag.OVERLAY_PERMISSION)) {
|
||||||
past.add(ManipulationWarningType.OverlayPermission)
|
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.OverlayPermission))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.wasAccessibilityServiceEnabled) {
|
if (device.wasAccessibilityServiceEnabled) {
|
||||||
if (!device.accessibilityServiceEnabled) {
|
if (!device.accessibilityServiceEnabled) {
|
||||||
current.add(ManipulationWarningType.AccessibilityService)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AccessibilityService))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isFlagSet(HadManipulationFlag.ACCESSIBILITY_SERVICE)) {
|
if (isFlagSet(HadManipulationFlag.ACCESSIBILITY_SERVICE)) {
|
||||||
past.add(ManipulationWarningType.AccessibilityService)
|
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AccessibilityService))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.manipulationDidReboot) {
|
if (device.manipulationDidReboot) {
|
||||||
current.add(ManipulationWarningType.DidReboot)
|
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.DidReboot))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.hadManipulation) {
|
if (device.hadManipulation) {
|
||||||
if (past.isEmpty()) {
|
if (past.isEmpty()) {
|
||||||
past.add(ManipulationWarningType.Unknown)
|
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.Unknown))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device.manipulationFlags != 0L) {
|
||||||
|
var remainingFlags = device.manipulationFlags
|
||||||
|
|
||||||
|
if (remainingFlags and ManipulationFlag.USED_FGS_KILLER == ManipulationFlag.USED_FGS_KILLER) {
|
||||||
|
past.add(ManipulationWarningType.Flag(ManipulationFlag.USED_FGS_KILLER, R.string.manage_device_manipulation_fgs_killer))
|
||||||
|
|
||||||
|
remainingFlags = remainingFlags.and(ManipulationFlag.USED_FGS_KILLER.inv())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingFlags != 0L) {
|
||||||
|
past.add(ManipulationWarningType.Flag(remainingFlags, R.string.manage_device_manipulation_unknown))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ManipulationWarnings(
|
return ManipulationWarnings(
|
||||||
current = current,
|
current = current,
|
||||||
past = past
|
past = past
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,38 +212,69 @@ data class ManipulationWarnings(val current: List<ManipulationWarningType>, val
|
||||||
|
|
||||||
fun buildIgnoreAction(deviceId: String): IgnoreManipulationAction {
|
fun buildIgnoreAction(deviceId: String): IgnoreManipulationAction {
|
||||||
var ignoreHadManipulationFlags = 0L
|
var ignoreHadManipulationFlags = 0L
|
||||||
|
var ignoreManipulationFlags = 0L
|
||||||
|
|
||||||
past.forEach { type ->
|
past.forEach { type ->
|
||||||
ignoreHadManipulationFlags = ignoreHadManipulationFlags or when(type) {
|
when (type) {
|
||||||
ManipulationWarningType.TriedDisablingDeviceAdmin -> throw IllegalArgumentException()
|
is ManipulationWarningType.Classic -> {
|
||||||
ManipulationWarningType.AppDowngrade -> HadManipulationFlag.APP_VERSION
|
ignoreHadManipulationFlags = ignoreHadManipulationFlags or when(type.type) {
|
||||||
ManipulationWarningType.DeviceAdmin -> HadManipulationFlag.PROTECTION_LEVEL
|
ClassicManipulationWarningType.TriedDisablingDeviceAdmin -> throw IllegalArgumentException()
|
||||||
ManipulationWarningType.UsageStats -> HadManipulationFlag.USAGE_STATS_ACCESS
|
ClassicManipulationWarningType.AppDowngrade -> HadManipulationFlag.APP_VERSION
|
||||||
ManipulationWarningType.NotificationAccess -> HadManipulationFlag.NOTIFICATION_ACCESS
|
ClassicManipulationWarningType.DeviceAdmin -> HadManipulationFlag.PROTECTION_LEVEL
|
||||||
ManipulationWarningType.OverlayPermission -> HadManipulationFlag.OVERLAY_PERMISSION
|
ClassicManipulationWarningType.UsageStats -> HadManipulationFlag.USAGE_STATS_ACCESS
|
||||||
ManipulationWarningType.AccessibilityService -> HadManipulationFlag.ACCESSIBILITY_SERVICE
|
ClassicManipulationWarningType.NotificationAccess -> HadManipulationFlag.NOTIFICATION_ACCESS
|
||||||
ManipulationWarningType.DidReboot -> throw IllegalArgumentException()
|
ClassicManipulationWarningType.OverlayPermission -> HadManipulationFlag.OVERLAY_PERMISSION
|
||||||
ManipulationWarningType.Unknown -> 0L // handled at an other location
|
ClassicManipulationWarningType.AccessibilityService -> HadManipulationFlag.ACCESSIBILITY_SERVICE
|
||||||
}
|
ClassicManipulationWarningType.DidReboot -> throw IllegalArgumentException()
|
||||||
|
ClassicManipulationWarningType.Unknown -> 0L // handled at an other location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ManipulationWarningType.Flag -> {
|
||||||
|
ignoreManipulationFlags = ignoreManipulationFlags or type.mask
|
||||||
|
}
|
||||||
|
}.let {/* require handling all cases */}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val currentClassic = current.filterIsInstance<ManipulationWarningType.Classic>().map { it.type }
|
||||||
|
|
||||||
return IgnoreManipulationAction(
|
return IgnoreManipulationAction(
|
||||||
deviceId = deviceId,
|
deviceId = deviceId,
|
||||||
ignoreUsageStatsAccessManipulation = current.contains(ManipulationWarningType.UsageStats),
|
ignoreUsageStatsAccessManipulation = currentClassic.contains(ClassicManipulationWarningType.UsageStats),
|
||||||
ignoreNotificationAccessManipulation = current.contains(ManipulationWarningType.NotificationAccess),
|
ignoreNotificationAccessManipulation = currentClassic.contains(ClassicManipulationWarningType.NotificationAccess),
|
||||||
ignoreDeviceAdminManipulationAttempt = current.contains(ManipulationWarningType.TriedDisablingDeviceAdmin),
|
ignoreDeviceAdminManipulationAttempt = currentClassic.contains(ClassicManipulationWarningType.TriedDisablingDeviceAdmin),
|
||||||
ignoreDeviceAdminManipulation = current.contains(ManipulationWarningType.DeviceAdmin),
|
ignoreDeviceAdminManipulation = currentClassic.contains(ClassicManipulationWarningType.DeviceAdmin),
|
||||||
ignoreOverlayPermissionManipulation = current.contains(ManipulationWarningType.OverlayPermission),
|
ignoreOverlayPermissionManipulation = currentClassic.contains(ClassicManipulationWarningType.OverlayPermission),
|
||||||
ignoreAccessibilityServiceManipulation = current.contains(ManipulationWarningType.AccessibilityService),
|
ignoreAccessibilityServiceManipulation = currentClassic.contains(ClassicManipulationWarningType.AccessibilityService),
|
||||||
ignoreAppDowngrade = current.contains(ManipulationWarningType.AppDowngrade),
|
ignoreAppDowngrade = currentClassic.contains(ClassicManipulationWarningType.AppDowngrade),
|
||||||
ignoreReboot = current.contains(ManipulationWarningType.DidReboot),
|
ignoreReboot = currentClassic.contains(ClassicManipulationWarningType.DidReboot),
|
||||||
ignoreHadManipulation = past.contains(ManipulationWarningType.Unknown),
|
ignoreHadManipulation = currentClassic.contains(ClassicManipulationWarningType.Unknown),
|
||||||
ignoreHadManipulationFlags = ignoreHadManipulationFlags
|
ignoreHadManipulationFlags = ignoreHadManipulationFlags,
|
||||||
|
ignoreManipulationFlags = ignoreManipulationFlags
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ManipulationWarningType {
|
sealed class ManipulationWarningType {
|
||||||
|
abstract val labelResourceId: Int
|
||||||
|
|
||||||
|
data class Classic(val type: ClassicManipulationWarningType): ManipulationWarningType() {
|
||||||
|
override val labelResourceId = when (type) {
|
||||||
|
ClassicManipulationWarningType.TriedDisablingDeviceAdmin -> R.string.manage_device_manipulation_device_admin_disable_attempt
|
||||||
|
ClassicManipulationWarningType.AppDowngrade -> R.string.manage_device_manipulation_app_version
|
||||||
|
ClassicManipulationWarningType.DeviceAdmin -> R.string.manage_device_manipulation_device_admin_disabled
|
||||||
|
ClassicManipulationWarningType.UsageStats -> R.string.manage_device_manipulation_usage_stats_access
|
||||||
|
ClassicManipulationWarningType.NotificationAccess -> R.string.manage_device_manipulation_notification_access
|
||||||
|
ClassicManipulationWarningType.OverlayPermission -> R.string.manage_device_manipulation_overlay_permission
|
||||||
|
ClassicManipulationWarningType.AccessibilityService -> R.string.manage_device_manipulation_accessibility_service
|
||||||
|
ClassicManipulationWarningType.DidReboot -> R.string.manage_device_manipulation_reboot
|
||||||
|
ClassicManipulationWarningType.Unknown -> R.string.manage_device_manipulation_existed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Flag(val mask: Long, override val labelResourceId: Int): ManipulationWarningType()
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ClassicManipulationWarningType {
|
||||||
TriedDisablingDeviceAdmin,
|
TriedDisablingDeviceAdmin,
|
||||||
AppDowngrade,
|
AppDowngrade,
|
||||||
DeviceAdmin,
|
DeviceAdmin,
|
||||||
|
@ -240,20 +286,6 @@ enum class ManipulationWarningType {
|
||||||
Unknown
|
Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
object ManipulationWarningTypeLabel {
|
|
||||||
fun getLabel(type: ManipulationWarningType) = when (type) {
|
|
||||||
ManipulationWarningType.TriedDisablingDeviceAdmin -> R.string.manage_device_manipulation_device_admin_disable_attempt
|
|
||||||
ManipulationWarningType.AppDowngrade -> R.string.manage_device_manipulation_app_version
|
|
||||||
ManipulationWarningType.DeviceAdmin -> R.string.manage_device_manipulation_device_admin_disabled
|
|
||||||
ManipulationWarningType.UsageStats -> R.string.manage_device_manipulation_usage_stats_access
|
|
||||||
ManipulationWarningType.NotificationAccess -> R.string.manage_device_manipulation_notification_access
|
|
||||||
ManipulationWarningType.OverlayPermission -> R.string.manage_device_manipulation_overlay_permission
|
|
||||||
ManipulationWarningType.AccessibilityService -> R.string.manage_device_manipulation_accessibility_service
|
|
||||||
ManipulationWarningType.DidReboot -> R.string.manage_device_manipulation_reboot
|
|
||||||
ManipulationWarningType.Unknown -> R.string.manage_device_manipulation_existed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ManageDeviceManipulationStatus {
|
class ManageDeviceManipulationStatus {
|
||||||
val selectedCurrent = mutableListOf<ManipulationWarningType>()
|
val selectedCurrent = mutableListOf<ManipulationWarningType>()
|
||||||
val selectedPast = mutableListOf<ManipulationWarningType>()
|
val selectedPast = mutableListOf<ManipulationWarningType>()
|
||||||
|
|
|
@ -35,7 +35,6 @@ import io.timelimit.android.ui.backdoor.BackdoorDialogFragment
|
||||||
import io.timelimit.android.ui.login.NewLoginFragment
|
import io.timelimit.android.ui.login.NewLoginFragment
|
||||||
import io.timelimit.android.ui.main.ActivityViewModel
|
import io.timelimit.android.ui.main.ActivityViewModel
|
||||||
import io.timelimit.android.ui.main.ActivityViewModelHolder
|
import io.timelimit.android.ui.main.ActivityViewModelHolder
|
||||||
import io.timelimit.android.ui.manage.device.manage.ManipulationWarningTypeLabel
|
|
||||||
import io.timelimit.android.ui.manage.device.manage.ManipulationWarnings
|
import io.timelimit.android.ui.manage.device.manage.ManipulationWarnings
|
||||||
import io.timelimit.android.util.TimeTextUtil
|
import io.timelimit.android.util.TimeTextUtil
|
||||||
|
|
||||||
|
@ -95,7 +94,7 @@ class AnnoyActivity : AppCompatActivity(), ActivityViewModelHolder {
|
||||||
logic.deviceEntry.map {
|
logic.deviceEntry.map {
|
||||||
val reasonItems = (it?.let { ManipulationWarnings.getFromDevice(it) } ?: ManipulationWarnings.empty)
|
val reasonItems = (it?.let { ManipulationWarnings.getFromDevice(it) } ?: ManipulationWarnings.empty)
|
||||||
.current
|
.current
|
||||||
.map { getString(ManipulationWarningTypeLabel.getLabel(it)) }
|
.map { getString(it.labelResourceId) }
|
||||||
|
|
||||||
if (reasonItems.isEmpty()) {
|
if (reasonItems.isEmpty()) {
|
||||||
null
|
null
|
||||||
|
|
|
@ -862,6 +862,8 @@
|
||||||
<string name="manage_device_manipulation_app_version">ältere App-Version installiert</string>
|
<string name="manage_device_manipulation_app_version">ältere App-Version installiert</string>
|
||||||
<string name="manage_device_manipulation_reboot">Gerät wurde neu gestartet</string>
|
<string name="manage_device_manipulation_reboot">Gerät wurde neu gestartet</string>
|
||||||
<string name="manage_device_manipulation_existed">Es gab eine Manipulation, die wieder beendet wurde</string>
|
<string name="manage_device_manipulation_existed">Es gab eine Manipulation, die wieder beendet wurde</string>
|
||||||
|
<string name="manage_device_manipulation_unknown">unbekannte Manipulation</string>
|
||||||
|
<string name="manage_device_manipulation_fgs_killer">mittels Task-Manager beendet</string>
|
||||||
<string name="manage_device_manipulation_btn_ignore">Warnungen bestätigen und ausblenden</string>
|
<string name="manage_device_manipulation_btn_ignore">Warnungen bestätigen und ausblenden</string>
|
||||||
<string name="manage_device_manipulation_toast_nothing_selected">Sie müssen zuerst Warnungen wählen, die Sie ignorieren möchten</string>
|
<string name="manage_device_manipulation_toast_nothing_selected">Sie müssen zuerst Warnungen wählen, die Sie ignorieren möchten</string>
|
||||||
|
|
||||||
|
|
|
@ -907,6 +907,8 @@
|
||||||
<string name="manage_device_manipulation_app_version">older App version installed</string>
|
<string name="manage_device_manipulation_app_version">older App version installed</string>
|
||||||
<string name="manage_device_manipulation_reboot">device was rebooted</string>
|
<string name="manage_device_manipulation_reboot">device was rebooted</string>
|
||||||
<string name="manage_device_manipulation_existed">there was a manipulation which was stopped again</string>
|
<string name="manage_device_manipulation_existed">there was a manipulation which was stopped again</string>
|
||||||
|
<string name="manage_device_manipulation_unknown">unknown Manipulation</string>
|
||||||
|
<string name="manage_device_manipulation_fgs_killer">killed using task manager</string>
|
||||||
<string name="manage_device_manipulation_btn_ignore">Confirm and hide warnings</string>
|
<string name="manage_device_manipulation_btn_ignore">Confirm and hide warnings</string>
|
||||||
<string name="manage_device_manipulation_toast_nothing_selected">You have to select warnings to ignore first</string>
|
<string name="manage_device_manipulation_toast_nothing_selected">You have to select warnings to ignore first</string>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue