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(
|
||||
MIGRATE_TO_V2,
|
||||
MIGRATE_TO_V3,
|
||||
|
@ -333,6 +339,7 @@ object DatabaseMigrations {
|
|||
MIGRATE_TO_V38,
|
||||
MIGRATE_TO_V39,
|
||||
MIGRATE_TO_V40,
|
||||
MIGRATE_TO_V41
|
||||
MIGRATE_TO_V41,
|
||||
MIGRATE_TO_V42
|
||||
)
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ import java.util.concurrent.TimeUnit
|
|||
CategoryNetworkId::class,
|
||||
ChildTask::class,
|
||||
CategoryTimeWarning::class
|
||||
], version = 41)
|
||||
], version = 42)
|
||||
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
||||
companion 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
|
||||
* 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")
|
||||
val enableActivityLevelBlocking: Boolean,
|
||||
@ColumnInfo(name = "q_or_later")
|
||||
val qOrLater: Boolean
|
||||
val qOrLater: Boolean,
|
||||
@ColumnInfo(name = "manipulation_flags")
|
||||
val manipulationFlags: Long
|
||||
): JsonSerializable {
|
||||
companion object {
|
||||
private const val ID = "id"
|
||||
|
@ -126,6 +128,7 @@ data class Device(
|
|||
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wase"
|
||||
private const val ENABLE_ACTIVITY_LEVEL_BLOCKING = "ealb"
|
||||
private const val Q_OR_LATER = "qol"
|
||||
private const val MANIPULATION_FLAGS = "mf"
|
||||
|
||||
fun parse(reader: JsonReader): Device {
|
||||
var id: String? = null
|
||||
|
@ -159,6 +162,7 @@ data class Device(
|
|||
var wasAccessibilityServiceEnabled = false
|
||||
var enableActivityLevelBlocking = false
|
||||
var qOrLater = false
|
||||
var manipulationFlags = 0L
|
||||
|
||||
reader.beginObject()
|
||||
|
||||
|
@ -195,6 +199,7 @@ data class Device(
|
|||
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
||||
ENABLE_ACTIVITY_LEVEL_BLOCKING -> enableActivityLevelBlocking = reader.nextBoolean()
|
||||
Q_OR_LATER -> qOrLater = reader.nextBoolean()
|
||||
MANIPULATION_FLAGS -> manipulationFlags = reader.nextLong()
|
||||
else -> reader.skipValue()
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +237,8 @@ data class Device(
|
|||
accessibilityServiceEnabled = accessibilityServiceEnabled,
|
||||
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled,
|
||||
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(ENABLE_ACTIVITY_LEVEL_BLOCKING).value(enableActivityLevelBlocking)
|
||||
writer.name(Q_OR_LATER).value(qOrLater)
|
||||
writer.name(MANIPULATION_FLAGS).value(manipulationFlags)
|
||||
|
||||
writer.endObject()
|
||||
}
|
||||
|
@ -331,7 +338,7 @@ data class Device(
|
|||
manipulationOfAccessibilityService
|
||||
|
||||
@Transient
|
||||
val hasAnyManipulation = hasActiveManipulationWarning || hadManipulation
|
||||
val hasAnyManipulation = hasActiveManipulationWarning || hadManipulation || manipulationFlags != 0L
|
||||
|
||||
@Transient
|
||||
val missingPermissionAtQOrLater = qOrLater &&
|
||||
|
@ -382,3 +389,7 @@ object HadManipulationFlag {
|
|||
const val OVERLAY_PERMISSION = 1L shl 4
|
||||
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
|
||||
): Boolean
|
||||
|
||||
abstract fun getExitLog(): List<ExitLogItem>
|
||||
abstract fun getExitLog(length: Int): List<ExitLogItem>
|
||||
|
||||
var installedAppsChangeListener: 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) {
|
||||
activityManager.getHistoricalProcessExitReasons(context.packageName, 0, 0)
|
||||
activityManager.getHistoricalProcessExitReasons(context.packageName, 0, length)
|
||||
.map { ExitLogItem.fromApplicationExitInfo(it) }
|
||||
} else emptyList()
|
||||
}
|
||||
|
|
|
@ -190,5 +190,5 @@ class DummyIntegration(
|
|||
confirmationLevel: SystemPermissionConfirmationLevel
|
||||
): 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,
|
||||
wasAccessibilityServiceEnabled = false,
|
||||
enableActivityLevelBlocking = false,
|
||||
qOrLater = AndroidVersion.qOrLater
|
||||
qOrLater = AndroidVersion.qOrLater,
|
||||
manipulationFlags = 0
|
||||
)
|
||||
|
||||
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.data.backup.DatabaseBackup
|
||||
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.derived.UserRelatedData
|
||||
import io.timelimit.android.date.DateInTimezone
|
||||
import io.timelimit.android.date.getMinuteOfWeek
|
||||
import io.timelimit.android.extensions.MinuteOfDay
|
||||
import io.timelimit.android.extensions.nextBlockedMinuteOfWeek
|
||||
import io.timelimit.android.integration.platform.AppStatusMessage
|
||||
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.*
|
||||
import io.timelimit.android.integration.platform.android.AccessibilityService
|
||||
import io.timelimit.android.livedata.*
|
||||
import io.timelimit.android.logic.blockingreason.AppBaseHandling
|
||||
|
@ -76,6 +74,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
runAsyncExpectForever { syncDeviceStatusLoop() }
|
||||
runAsyncExpectForever { backupDatabaseLoop() }
|
||||
runAsyncExpectForever { annoyUserOnManipulationLoop() }
|
||||
runAsync { checkForceKilled() }
|
||||
runAsync {
|
||||
// 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()
|
||||
|
||||
fun reportDeviceReboot() {
|
||||
|
|
|
@ -188,7 +188,8 @@ object ApplyServerDataStatus {
|
|||
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
||||
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
||||
qOrLater = newDevice.qOrLater
|
||||
qOrLater = newDevice.qOrLater,
|
||||
manipulationFlags = newDevice.manipulationFlags
|
||||
))
|
||||
} else {
|
||||
// eventually update old entry
|
||||
|
@ -222,7 +223,8 @@ object ApplyServerDataStatus {
|
|||
accessibilityServiceEnabled = newDevice.accessibilityServiceEnabled,
|
||||
wasAccessibilityServiceEnabled = newDevice.wasAccessibilityServiceEnabled,
|
||||
enableActivityLevelBlocking = newDevice.enableActivityLevelBlocking,
|
||||
qOrLater = newDevice.qOrLater
|
||||
qOrLater = newDevice.qOrLater,
|
||||
manipulationFlags = newDevice.manipulationFlags
|
||||
)
|
||||
|
||||
if (updatedDeviceEntry != oldDeviceEntry) {
|
||||
|
|
|
@ -1081,7 +1081,8 @@ data class UpdateDeviceStatusAction(
|
|||
val newAccessibilityServiceEnabled: Boolean?,
|
||||
val newAppVersion: Int?,
|
||||
val didReboot: Boolean,
|
||||
val isQOrLaterNow: Boolean
|
||||
val isQOrLaterNow: Boolean,
|
||||
val addedManipulationFlags: Long
|
||||
): AppLogicAction() {
|
||||
companion object {
|
||||
const val TYPE_VALUE = "UPDATE_DEVICE_STATUS"
|
||||
|
@ -1093,6 +1094,7 @@ data class UpdateDeviceStatusAction(
|
|||
private const val NEW_APP_VERSION = "appVersion"
|
||||
private const val DID_REBOOT = "didReboot"
|
||||
private const val IS_Q_OR_LATER_NOW = "isQOrLaterNow"
|
||||
private const val ADDED_MANIPULATION_FLAGS = "addedManipulationFlags"
|
||||
|
||||
val empty = UpdateDeviceStatusAction(
|
||||
newProtectionLevel = null,
|
||||
|
@ -1102,7 +1104,8 @@ data class UpdateDeviceStatusAction(
|
|||
newAccessibilityServiceEnabled = null,
|
||||
newAppVersion = null,
|
||||
didReboot = false,
|
||||
isQOrLaterNow = false
|
||||
isQOrLaterNow = false,
|
||||
addedManipulationFlags = 0L
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1159,6 +1162,10 @@ data class UpdateDeviceStatusAction(
|
|||
writer.name(IS_Q_OR_LATER_NOW).value(true)
|
||||
}
|
||||
|
||||
if (addedManipulationFlags != 0L) {
|
||||
writer.name(ADDED_MANIPULATION_FLAGS).value(addedManipulationFlags)
|
||||
}
|
||||
|
||||
writer.endObject()
|
||||
}
|
||||
}
|
||||
|
@ -1174,7 +1181,8 @@ data class IgnoreManipulationAction(
|
|||
val ignoreAccessibilityServiceManipulation: Boolean,
|
||||
val ignoreReboot: Boolean,
|
||||
val ignoreHadManipulation: Boolean,
|
||||
val ignoreHadManipulationFlags: Long
|
||||
val ignoreHadManipulationFlags: Long,
|
||||
val ignoreManipulationFlags: Long
|
||||
): ParentAction() {
|
||||
companion object {
|
||||
const val TYPE_VALUE = "IGNORE_MANIPULATION"
|
||||
|
@ -1189,6 +1197,7 @@ data class IgnoreManipulationAction(
|
|||
private const val IGNORE_HAD_MANIPULATION = "hadManipulation"
|
||||
private const val IGNORE_REBOOT = "reboot"
|
||||
private const val IGNORE_HAD_MANIPULATION_FLAGS = "ignoreHadManipulationFlags"
|
||||
private const val IGNORE_MANIPULATION_FLAGS = "ignoreManipulationFlags"
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -1204,7 +1213,8 @@ data class IgnoreManipulationAction(
|
|||
(!ignoreAccessibilityServiceManipulation) &&
|
||||
(!ignoreReboot) &&
|
||||
(!ignoreHadManipulation) &&
|
||||
(ignoreHadManipulationFlags == 0L)
|
||||
(ignoreHadManipulationFlags == 0L) &&
|
||||
(ignoreManipulationFlags == 0L)
|
||||
|
||||
override fun serialize(writer: JsonWriter) {
|
||||
writer.beginObject()
|
||||
|
@ -1222,6 +1232,8 @@ data class IgnoreManipulationAction(
|
|||
writer.name(IGNORE_REBOOT).value(ignoreReboot)
|
||||
writer.name(IGNORE_HAD_MANIPULATION_FLAGS).value(ignoreHadManipulationFlags)
|
||||
|
||||
if (ignoreManipulationFlags != 0L) writer.name(IGNORE_MANIPULATION_FLAGS).value(ignoreManipulationFlags)
|
||||
|
||||
writer.endObject()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,6 +305,10 @@ object LocalDatabaseAppLogicActionDispatcher {
|
|||
device = device.copy(qOrLater = true)
|
||||
}
|
||||
|
||||
if (action.addedManipulationFlags != 0L) {
|
||||
device = device.copy(manipulationFlags = device.manipulationFlags or action.addedManipulationFlags)
|
||||
}
|
||||
|
||||
database.device().updateDeviceEntry(device)
|
||||
|
||||
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)
|
||||
}
|
||||
is SetKeepSignedInAction -> {
|
||||
|
|
|
@ -298,7 +298,8 @@ data class ServerDeviceData(
|
|||
val accessibilityServiceEnabled: Boolean,
|
||||
val wasAccessibilityServiceEnabled: Boolean,
|
||||
val enableActivityLevelBlocking: Boolean,
|
||||
val qOrLater: Boolean
|
||||
val qOrLater: Boolean,
|
||||
val manipulationFlags: Long
|
||||
) {
|
||||
companion object {
|
||||
private const val DEVICE_ID = "deviceId"
|
||||
|
@ -331,6 +332,7 @@ data class ServerDeviceData(
|
|||
private const val WAS_ACCESSIBILITY_SERVICE_ENABLED = "wasAsEnabled"
|
||||
private const val ENABLE_ACTIVITY_LEVEL_BLOCKING = "activityLevelBlocking"
|
||||
private const val Q_OR_LATER = "qOrLater"
|
||||
private const val MANIPULATION_FLAGS = "mFlags"
|
||||
|
||||
fun parse(reader: JsonReader): ServerDeviceData {
|
||||
var deviceId: String? = null
|
||||
|
@ -363,6 +365,7 @@ data class ServerDeviceData(
|
|||
var wasAccessibilityServiceEnabled: Boolean? = null
|
||||
var enableActivityLevelBlocking = false
|
||||
var qOrLater = false
|
||||
var manipulationFlags = 0L
|
||||
|
||||
reader.beginObject()
|
||||
while (reader.hasNext()) {
|
||||
|
@ -397,6 +400,7 @@ data class ServerDeviceData(
|
|||
WAS_ACCESSIBILITY_SERVICE_ENABLED -> wasAccessibilityServiceEnabled = reader.nextBoolean()
|
||||
ENABLE_ACTIVITY_LEVEL_BLOCKING -> enableActivityLevelBlocking = reader.nextBoolean()
|
||||
Q_OR_LATER -> qOrLater = reader.nextBoolean()
|
||||
MANIPULATION_FLAGS -> manipulationFlags = reader.nextLong()
|
||||
else -> reader.skipValue()
|
||||
}
|
||||
}
|
||||
|
@ -432,7 +436,8 @@ data class ServerDeviceData(
|
|||
accessibilityServiceEnabled = accessibilityServiceEnabled!!,
|
||||
wasAccessibilityServiceEnabled = wasAccessibilityServiceEnabled!!,
|
||||
enableActivityLevelBlocking = enableActivityLevelBlocking,
|
||||
qOrLater = qOrLater
|
||||
qOrLater = qOrLater,
|
||||
manipulationFlags = manipulationFlags
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ import io.timelimit.android.ui.main.FragmentWithCustomTitle
|
|||
class DiagnoseExitReasonFragment: Fragment(), FragmentWithCustomTitle {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
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 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
|
||||
* 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.data.model.Device
|
||||
import io.timelimit.android.data.model.HadManipulationFlag
|
||||
import io.timelimit.android.data.model.ManipulationFlag
|
||||
import io.timelimit.android.databinding.ManageDeviceManipulationViewBinding
|
||||
import io.timelimit.android.livedata.map
|
||||
import io.timelimit.android.sync.actions.IgnoreManipulationAction
|
||||
|
@ -62,7 +63,7 @@ object ManageDeviceManipulation {
|
|||
entries.forEach { warning ->
|
||||
container.addView(
|
||||
createCheckbox().apply {
|
||||
setText(ManipulationWarningTypeLabel.getLabel(warning))
|
||||
setText(warning.labelResourceId)
|
||||
isChecked = selection.contains(warning)
|
||||
|
||||
setOnCheckedChangeListener { _, newIsChecked ->
|
||||
|
@ -128,60 +129,74 @@ data class ManipulationWarnings(val current: List<ManipulationWarningType>, val
|
|||
fun isFlagSet(flag: Long) = (manipulationFlags and flag) == flag
|
||||
|
||||
if (device.manipulationTriedDisablingDeviceAdmin) {
|
||||
current.add(ManipulationWarningType.TriedDisablingDeviceAdmin)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.TriedDisablingDeviceAdmin))
|
||||
}
|
||||
|
||||
if (device.manipulationOfAppVersion) {
|
||||
current.add(ManipulationWarningType.AppDowngrade)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AppDowngrade))
|
||||
}
|
||||
if (isFlagSet(HadManipulationFlag.APP_VERSION)) {
|
||||
past.add(ManipulationWarningType.AppDowngrade)
|
||||
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AppDowngrade))
|
||||
}
|
||||
|
||||
if (device.manipulationOfProtectionLevel) {
|
||||
current.add(ManipulationWarningType.DeviceAdmin)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.DeviceAdmin))
|
||||
}
|
||||
if (isFlagSet(HadManipulationFlag.PROTECTION_LEVEL)) {
|
||||
past.add(ManipulationWarningType.DeviceAdmin)
|
||||
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.DeviceAdmin))
|
||||
}
|
||||
|
||||
if (device.manipulationOfUsageStats) {
|
||||
current.add(ManipulationWarningType.UsageStats)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.UsageStats))
|
||||
}
|
||||
if (isFlagSet(HadManipulationFlag.USAGE_STATS_ACCESS)) {
|
||||
past.add(ManipulationWarningType.UsageStats)
|
||||
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.UsageStats))
|
||||
}
|
||||
|
||||
if (device.manipulationOfNotificationAccess) {
|
||||
current.add(ManipulationWarningType.NotificationAccess)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.NotificationAccess))
|
||||
}
|
||||
if (isFlagSet(HadManipulationFlag.NOTIFICATION_ACCESS)) {
|
||||
past.add(ManipulationWarningType.NotificationAccess)
|
||||
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.NotificationAccess))
|
||||
}
|
||||
|
||||
if (device.manipulationOfOverlayPermission) {
|
||||
current.add(ManipulationWarningType.OverlayPermission)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.OverlayPermission))
|
||||
}
|
||||
if (isFlagSet(HadManipulationFlag.OVERLAY_PERMISSION)) {
|
||||
past.add(ManipulationWarningType.OverlayPermission)
|
||||
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.OverlayPermission))
|
||||
}
|
||||
|
||||
if (device.wasAccessibilityServiceEnabled) {
|
||||
if (!device.accessibilityServiceEnabled) {
|
||||
current.add(ManipulationWarningType.AccessibilityService)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AccessibilityService))
|
||||
}
|
||||
}
|
||||
if (isFlagSet(HadManipulationFlag.ACCESSIBILITY_SERVICE)) {
|
||||
past.add(ManipulationWarningType.AccessibilityService)
|
||||
past.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.AccessibilityService))
|
||||
}
|
||||
|
||||
if (device.manipulationDidReboot) {
|
||||
current.add(ManipulationWarningType.DidReboot)
|
||||
current.add(ManipulationWarningType.Classic(ClassicManipulationWarningType.DidReboot))
|
||||
}
|
||||
|
||||
if (device.hadManipulation) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,38 +212,69 @@ data class ManipulationWarnings(val current: List<ManipulationWarningType>, val
|
|||
|
||||
fun buildIgnoreAction(deviceId: String): IgnoreManipulationAction {
|
||||
var ignoreHadManipulationFlags = 0L
|
||||
var ignoreManipulationFlags = 0L
|
||||
|
||||
past.forEach { type ->
|
||||
ignoreHadManipulationFlags = ignoreHadManipulationFlags or when(type) {
|
||||
ManipulationWarningType.TriedDisablingDeviceAdmin -> throw IllegalArgumentException()
|
||||
ManipulationWarningType.AppDowngrade -> HadManipulationFlag.APP_VERSION
|
||||
ManipulationWarningType.DeviceAdmin -> HadManipulationFlag.PROTECTION_LEVEL
|
||||
ManipulationWarningType.UsageStats -> HadManipulationFlag.USAGE_STATS_ACCESS
|
||||
ManipulationWarningType.NotificationAccess -> HadManipulationFlag.NOTIFICATION_ACCESS
|
||||
ManipulationWarningType.OverlayPermission -> HadManipulationFlag.OVERLAY_PERMISSION
|
||||
ManipulationWarningType.AccessibilityService -> HadManipulationFlag.ACCESSIBILITY_SERVICE
|
||||
ManipulationWarningType.DidReboot -> throw IllegalArgumentException()
|
||||
ManipulationWarningType.Unknown -> 0L // handled at an other location
|
||||
when (type) {
|
||||
is ManipulationWarningType.Classic -> {
|
||||
ignoreHadManipulationFlags = ignoreHadManipulationFlags or when(type.type) {
|
||||
ClassicManipulationWarningType.TriedDisablingDeviceAdmin -> throw IllegalArgumentException()
|
||||
ClassicManipulationWarningType.AppDowngrade -> HadManipulationFlag.APP_VERSION
|
||||
ClassicManipulationWarningType.DeviceAdmin -> HadManipulationFlag.PROTECTION_LEVEL
|
||||
ClassicManipulationWarningType.UsageStats -> HadManipulationFlag.USAGE_STATS_ACCESS
|
||||
ClassicManipulationWarningType.NotificationAccess -> HadManipulationFlag.NOTIFICATION_ACCESS
|
||||
ClassicManipulationWarningType.OverlayPermission -> HadManipulationFlag.OVERLAY_PERMISSION
|
||||
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(
|
||||
deviceId = deviceId,
|
||||
ignoreUsageStatsAccessManipulation = current.contains(ManipulationWarningType.UsageStats),
|
||||
ignoreNotificationAccessManipulation = current.contains(ManipulationWarningType.NotificationAccess),
|
||||
ignoreDeviceAdminManipulationAttempt = current.contains(ManipulationWarningType.TriedDisablingDeviceAdmin),
|
||||
ignoreDeviceAdminManipulation = current.contains(ManipulationWarningType.DeviceAdmin),
|
||||
ignoreOverlayPermissionManipulation = current.contains(ManipulationWarningType.OverlayPermission),
|
||||
ignoreAccessibilityServiceManipulation = current.contains(ManipulationWarningType.AccessibilityService),
|
||||
ignoreAppDowngrade = current.contains(ManipulationWarningType.AppDowngrade),
|
||||
ignoreReboot = current.contains(ManipulationWarningType.DidReboot),
|
||||
ignoreHadManipulation = past.contains(ManipulationWarningType.Unknown),
|
||||
ignoreHadManipulationFlags = ignoreHadManipulationFlags
|
||||
ignoreUsageStatsAccessManipulation = currentClassic.contains(ClassicManipulationWarningType.UsageStats),
|
||||
ignoreNotificationAccessManipulation = currentClassic.contains(ClassicManipulationWarningType.NotificationAccess),
|
||||
ignoreDeviceAdminManipulationAttempt = currentClassic.contains(ClassicManipulationWarningType.TriedDisablingDeviceAdmin),
|
||||
ignoreDeviceAdminManipulation = currentClassic.contains(ClassicManipulationWarningType.DeviceAdmin),
|
||||
ignoreOverlayPermissionManipulation = currentClassic.contains(ClassicManipulationWarningType.OverlayPermission),
|
||||
ignoreAccessibilityServiceManipulation = currentClassic.contains(ClassicManipulationWarningType.AccessibilityService),
|
||||
ignoreAppDowngrade = currentClassic.contains(ClassicManipulationWarningType.AppDowngrade),
|
||||
ignoreReboot = currentClassic.contains(ClassicManipulationWarningType.DidReboot),
|
||||
ignoreHadManipulation = currentClassic.contains(ClassicManipulationWarningType.Unknown),
|
||||
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,
|
||||
AppDowngrade,
|
||||
DeviceAdmin,
|
||||
|
@ -240,20 +286,6 @@ enum class ManipulationWarningType {
|
|||
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 {
|
||||
val selectedCurrent = 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.main.ActivityViewModel
|
||||
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.util.TimeTextUtil
|
||||
|
||||
|
@ -95,7 +94,7 @@ class AnnoyActivity : AppCompatActivity(), ActivityViewModelHolder {
|
|||
logic.deviceEntry.map {
|
||||
val reasonItems = (it?.let { ManipulationWarnings.getFromDevice(it) } ?: ManipulationWarnings.empty)
|
||||
.current
|
||||
.map { getString(ManipulationWarningTypeLabel.getLabel(it)) }
|
||||
.map { getString(it.labelResourceId) }
|
||||
|
||||
if (reasonItems.isEmpty()) {
|
||||
null
|
||||
|
|
|
@ -862,6 +862,8 @@
|
|||
<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_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_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_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_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_toast_nothing_selected">You have to select warnings to ignore first</string>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue