mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-05 10:49:26 +02:00
Add option to block Apps at system level
This commit is contained in:
parent
3fbf598eb5
commit
03bd3a5100
13 changed files with 427 additions and 18 deletions
|
@ -223,7 +223,8 @@ abstract class ConfigDao {
|
|||
|
||||
fun getEnableAlternativeDurationSelectionAsync() = getValueOfKeyAsync(ConfigurationItemType.EnableAlternativeDurationSelection).map { it == "1" }
|
||||
fun setEnableAlternativeDurationSelectionSync(enable: Boolean) = updateValueSync(ConfigurationItemType.EnableAlternativeDurationSelection, if (enable) "1" else "0")
|
||||
fun getExperimentalFlagsLive(): LiveData<Long> {
|
||||
|
||||
protected fun getExperimentalFlagsLive(): LiveData<Long> {
|
||||
return getValueOfKeyAsync(ConfigurationItemType.ExperimentalFlags).map {
|
||||
if (it == null) {
|
||||
0
|
||||
|
@ -233,6 +234,8 @@ abstract class ConfigDao {
|
|||
}
|
||||
}
|
||||
|
||||
val experimentalFlags: LiveData<Long> by lazy { getExperimentalFlagsLive() }
|
||||
|
||||
private fun getExperimentalFlagsSync(): Long {
|
||||
val v = getValueOfKeySync(ConfigurationItemType.ExperimentalFlags)
|
||||
|
||||
|
@ -243,7 +246,7 @@ abstract class ConfigDao {
|
|||
}
|
||||
}
|
||||
|
||||
fun isExperimentalFlagsSetAsync(flags: Long) = getExperimentalFlagsLive().map {
|
||||
fun isExperimentalFlagsSetAsync(flags: Long) = experimentalFlags.map {
|
||||
(it and flags) == flags
|
||||
}.ignoreUnchanged()
|
||||
|
||||
|
@ -253,9 +256,9 @@ abstract class ConfigDao {
|
|||
updateValueSync(
|
||||
ConfigurationItemType.ExperimentalFlags,
|
||||
if (enable)
|
||||
(getShownHintsSync() or flags).toString(16)
|
||||
(getExperimentalFlagsSync() or flags).toString(16)
|
||||
else
|
||||
(getShownHintsSync() and (flags.inv())).toString(16)
|
||||
(getExperimentalFlagsSync() and (flags.inv())).toString(16)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,4 +191,5 @@ object HintsToShow {
|
|||
|
||||
object ExperimentalFlags {
|
||||
const val DISABLE_BLOCK_ON_MANIPULATION = 1L
|
||||
const val SYSTEM_LEVEL_BLOCKING = 2L
|
||||
}
|
|
@ -52,6 +52,12 @@ object AndroidIntegrationApps {
|
|||
ignoredApps["com.google.android.packageinstaller"] = AndroidIntegrationApps.IgnoredAppHandling.IgnoreOnStoreOtherwiseWhitelistAndDontDisable
|
||||
}
|
||||
|
||||
private val ignoredActivities = setOf<String>(
|
||||
"com.android.settings:com.android.settings.enterprise.ActionDisabledByAdminDialog"
|
||||
)
|
||||
|
||||
fun shouldIgnoreActivity(packageName: String, activityName: String) = ignoredActivities.contains("$packageName:$activityName")
|
||||
|
||||
fun getLocalApps(deviceId: String, context: Context): Collection<App> {
|
||||
val packageManager = context.packageManager
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ class AppLogic(
|
|||
}
|
||||
|
||||
val manipulationLogic = ManipulationLogic(this)
|
||||
val suspendAppsLogic = SuspendAppsLogic(this)
|
||||
|
||||
fun shutdown() {
|
||||
enable.value = false
|
||||
|
|
|
@ -296,7 +296,9 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
AndroidIntegrationApps.IgnoredAppHandling.Ignore -> true
|
||||
AndroidIntegrationApps.IgnoredAppHandling.IgnoreOnStoreOtherwiseWhitelistAndDontDisable -> BuildConfig.storeCompilant
|
||||
}
|
||||
})
|
||||
}) ||
|
||||
(foregroundAppPackageName != null && foregroundAppActivityName != null &&
|
||||
AndroidIntegrationApps.shouldIgnoreActivity(foregroundAppPackageName, foregroundAppActivityName))
|
||||
) {
|
||||
usedTimeUpdateHelper?.commit(appLogic)
|
||||
showStatusMessageWithCurrentAppTitle(
|
||||
|
|
|
@ -357,7 +357,7 @@ class BlockingReasonUtil(private val appLogic: AppLogic) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun getTemporarilyTrustedTimeInMillis(): LiveData<Long?> {
|
||||
fun getTemporarilyTrustedTimeInMillis(): LiveData<Long?> {
|
||||
val realTime = RealTime.newInstance()
|
||||
|
||||
return liveDataFromFunction {
|
||||
|
@ -417,7 +417,7 @@ class BlockingReasonUtil(private val appLogic: AppLogic) {
|
|||
}.ignoreUnchanged()
|
||||
}
|
||||
|
||||
private fun getTrustedDateLive(timeZone: TimeZone): LiveData<DateInTimezone?> {
|
||||
fun getTrustedDateLive(timeZone: TimeZone): LiveData<DateInTimezone?> {
|
||||
val realTime = RealTime.newInstance()
|
||||
|
||||
return object: LiveData<DateInTimezone?>() {
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 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
|
||||
* the Free Software Foundation version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.timelimit.android.logic
|
||||
|
||||
import android.util.Log
|
||||
import android.util.SparseLongArray
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import io.timelimit.android.BuildConfig
|
||||
import io.timelimit.android.data.model.*
|
||||
import io.timelimit.android.date.DateInTimezone
|
||||
import io.timelimit.android.livedata.*
|
||||
import java.util.*
|
||||
|
||||
class CategoriesBlockingReasonUtil(private val appLogic: AppLogic) {
|
||||
companion object {
|
||||
private const val LOG_TAG = "CategoryBlockingReason"
|
||||
}
|
||||
|
||||
private val blockingReason = BlockingReasonUtil(appLogic)
|
||||
private val temporarilyTrustedTimeInMillis = blockingReason.getTemporarilyTrustedTimeInMillis()
|
||||
|
||||
// NOTE: this ignores the current device rule
|
||||
fun getCategoryBlockingReasons(
|
||||
childDisableLimitsUntil: LiveData<Long>,
|
||||
timeZone: LiveData<TimeZone>,
|
||||
categories: List<Category>
|
||||
): LiveData<Map<String, BlockingReason>> {
|
||||
val result = MediatorLiveData<Map<String, BlockingReason>>()
|
||||
val status = mutableMapOf<String, BlockingReason>()
|
||||
|
||||
val reasons = getCategoryBlockingReasonsInternal(childDisableLimitsUntil, timeZone, categories)
|
||||
var missing = reasons.size
|
||||
|
||||
reasons.entries.forEach { (k, v) ->
|
||||
var ready = false
|
||||
|
||||
result.addSource(v) { newStatus ->
|
||||
status[k] = newStatus
|
||||
|
||||
if (!ready) {
|
||||
ready = true
|
||||
missing--
|
||||
}
|
||||
|
||||
if (missing == 0) {
|
||||
result.value = status.toMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// NOTE: this ignores the current device rule
|
||||
private fun getCategoryBlockingReasonsInternal(
|
||||
childDisableLimitsUntil: LiveData<Long>,
|
||||
timeZone: LiveData<TimeZone>,
|
||||
categories: List<Category>
|
||||
): Map<String, LiveData<BlockingReason>> {
|
||||
val result = mutableMapOf<String, LiveData<BlockingReason>>()
|
||||
val categoryById = categories.associateBy { it.id }
|
||||
|
||||
val areLimitsTemporarilyDisabled = areLimitsDisabled(
|
||||
temporarilyTrustedTimeInMillis = temporarilyTrustedTimeInMillis,
|
||||
childDisableLimitsUntil = childDisableLimitsUntil
|
||||
)
|
||||
|
||||
val temporarilyTrustedMinuteOfWeek = timeZone.switchMap { timeZone ->
|
||||
blockingReason.getTrustedMinuteOfWeekLive(timeZone)
|
||||
}
|
||||
|
||||
val temporarilyTrustedDate = timeZone.switchMap { timeZone ->
|
||||
blockingReason.getTrustedDateLive(timeZone)
|
||||
}
|
||||
|
||||
fun handleCategory(categoryId: String) {
|
||||
categoryById[categoryId]?.let { category ->
|
||||
result[categoryId] = result[categoryId] ?: getCategoryBlockingReason(
|
||||
category = liveDataFromValue(category),
|
||||
temporarilyTrustedMinuteOfWeek = temporarilyTrustedMinuteOfWeek,
|
||||
temporarilyTrustedDate = temporarilyTrustedDate,
|
||||
areLimitsTemporarilyDisabled = areLimitsTemporarilyDisabled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
categoryById.keys.forEach { handleCategory(it) }
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// NOTE: this ignores parent categories (otherwise would check parent category if category has no blocking reason)
|
||||
// NOTE: this ignores the current device rule
|
||||
private fun getCategoryBlockingReason(
|
||||
category: LiveData<Category>,
|
||||
temporarilyTrustedMinuteOfWeek: LiveData<Int?>,
|
||||
temporarilyTrustedDate: LiveData<DateInTimezone?>,
|
||||
areLimitsTemporarilyDisabled: LiveData<Boolean>
|
||||
): LiveData<BlockingReason> {
|
||||
return category.switchMap { category ->
|
||||
if (category.temporarilyBlocked) {
|
||||
liveDataFromValue(BlockingReason.TemporarilyBlocked)
|
||||
} else {
|
||||
areLimitsTemporarilyDisabled.switchMap { areLimitsTemporarilyDisabled ->
|
||||
if (areLimitsTemporarilyDisabled) {
|
||||
liveDataFromValue(BlockingReason.None)
|
||||
} else {
|
||||
checkCategoryBlockedTimeAreas(
|
||||
temporarilyTrustedMinuteOfWeek = temporarilyTrustedMinuteOfWeek,
|
||||
blockedMinutesInWeek = category.blockedMinutesInWeek.dataNotToModify
|
||||
).switchMap { blockedTimeAreasReason ->
|
||||
if (blockedTimeAreasReason != BlockingReason.None) {
|
||||
liveDataFromValue(blockedTimeAreasReason)
|
||||
} else {
|
||||
checkCategoryTimeLimitRules(
|
||||
temporarilyTrustedDate = temporarilyTrustedDate,
|
||||
category = category,
|
||||
rules = appLogic.database.timeLimitRules().getTimeLimitRulesByCategory(category.id)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun areLimitsDisabled(
|
||||
temporarilyTrustedTimeInMillis: LiveData<Long?>,
|
||||
childDisableLimitsUntil: LiveData<Long>
|
||||
): LiveData<Boolean> = childDisableLimitsUntil.switchMap { childDisableLimitsUntil ->
|
||||
if (childDisableLimitsUntil == 0L) {
|
||||
liveDataFromValue(false)
|
||||
} else {
|
||||
temporarilyTrustedTimeInMillis.map {
|
||||
trustedTimeInMillis ->
|
||||
|
||||
trustedTimeInMillis != null && childDisableLimitsUntil > trustedTimeInMillis
|
||||
}.ignoreUnchanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCategoryBlockedTimeAreas(blockedMinutesInWeek: BitSet, temporarilyTrustedMinuteOfWeek: LiveData<Int?>): LiveData<BlockingReason> {
|
||||
if (blockedMinutesInWeek.isEmpty) {
|
||||
return liveDataFromValue(BlockingReason.None)
|
||||
} else {
|
||||
return temporarilyTrustedMinuteOfWeek.map { temporarilyTrustedMinuteOfWeek ->
|
||||
if (temporarilyTrustedMinuteOfWeek == null) {
|
||||
BlockingReason.MissingNetworkTime
|
||||
} else if (blockedMinutesInWeek[temporarilyTrustedMinuteOfWeek]) {
|
||||
BlockingReason.BlockedAtThisTime
|
||||
} else {
|
||||
BlockingReason.None
|
||||
}
|
||||
}.ignoreUnchanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCategoryTimeLimitRules(
|
||||
temporarilyTrustedDate: LiveData<DateInTimezone?>,
|
||||
rules: LiveData<List<TimeLimitRule>>,
|
||||
category: Category
|
||||
): LiveData<BlockingReason> = rules.switchMap { rules ->
|
||||
if (rules.isEmpty()) {
|
||||
liveDataFromValue(BlockingReason.None)
|
||||
} else {
|
||||
temporarilyTrustedDate.switchMap { temporarilyTrustedDate ->
|
||||
if (temporarilyTrustedDate == null) {
|
||||
liveDataFromValue(BlockingReason.MissingNetworkTime)
|
||||
} else {
|
||||
getBlockingReasonStep7(
|
||||
category = category,
|
||||
nowTrustedDate = temporarilyTrustedDate,
|
||||
rules = rules
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBlockingReasonStep7(category: Category, nowTrustedDate: DateInTimezone, rules: List<TimeLimitRule>): LiveData<BlockingReason> {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(LOG_TAG, "step 7")
|
||||
}
|
||||
|
||||
return appLogic.database.usedTimes().getUsedTimesOfWeek(category.id, nowTrustedDate.dayOfEpoch - nowTrustedDate.dayOfWeek).map { usedTimes ->
|
||||
val usedTimesSparseArray = SparseLongArray()
|
||||
|
||||
for (i in 0..6) {
|
||||
val usedTimesItem = usedTimes[i]?.usedMillis
|
||||
usedTimesSparseArray.put(i, (if (usedTimesItem != null) usedTimesItem else 0))
|
||||
}
|
||||
|
||||
val remaining = RemainingTime.getRemainingTime(nowTrustedDate.dayOfWeek, usedTimesSparseArray, rules, category.extraTimeInMillis)
|
||||
|
||||
if (remaining == null || remaining.includingExtraTime > 0) {
|
||||
BlockingReason.None
|
||||
} else {
|
||||
if (category.extraTimeInMillis > 0) {
|
||||
BlockingReason.TimeOverExtraTimeCanBeUsedLater
|
||||
} else {
|
||||
BlockingReason.TimeOver
|
||||
}
|
||||
}
|
||||
}.ignoreUnchanged()
|
||||
}
|
||||
}
|
163
app/src/main/java/io/timelimit/android/logic/SuspendAppsLogic.kt
Normal file
163
app/src/main/java/io/timelimit/android/logic/SuspendAppsLogic.kt
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 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
|
||||
* the Free Software Foundation version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.timelimit.android.logic
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import io.timelimit.android.data.model.Category
|
||||
import io.timelimit.android.data.model.CategoryApp
|
||||
import io.timelimit.android.data.model.ExperimentalFlags
|
||||
import io.timelimit.android.data.model.UserType
|
||||
import io.timelimit.android.livedata.ignoreUnchanged
|
||||
import io.timelimit.android.livedata.liveDataFromValue
|
||||
import io.timelimit.android.livedata.map
|
||||
import io.timelimit.android.livedata.switchMap
|
||||
import java.util.*
|
||||
|
||||
class SuspendAppsLogic(private val appLogic: AppLogic) {
|
||||
private val blockingAtActivityLevel = appLogic.deviceEntry.map { it?.enableActivityLevelBlocking ?: false }
|
||||
private val blockingReasonUtil = CategoriesBlockingReasonUtil(appLogic)
|
||||
|
||||
private val knownInstalledApps = appLogic.deviceId.switchMap { deviceId ->
|
||||
if (deviceId.isNullOrEmpty()) {
|
||||
liveDataFromValue(emptyList())
|
||||
} else {
|
||||
appLogic.database.app().getAppsByDeviceIdAsync(deviceId).map { apps ->
|
||||
apps.map { it.packageName }
|
||||
}
|
||||
}
|
||||
}.ignoreUnchanged()
|
||||
|
||||
private val categoryData = appLogic.deviceUserEntry.switchMap { deviceUser ->
|
||||
if (deviceUser?.type == UserType.Child) {
|
||||
appLogic.database.category().getCategoriesByChildId(deviceUser.id).switchMap { categories ->
|
||||
appLogic.database.categoryApp().getCategoryApps(categories.map { it.id }).map { categoryApps ->
|
||||
RealCategoryData(
|
||||
categoryForUnassignedApps = deviceUser.categoryForNotAssignedApps,
|
||||
categories = categories,
|
||||
categoryApps = categoryApps
|
||||
) as CategoryData
|
||||
}
|
||||
}
|
||||
} else {
|
||||
liveDataFromValue(NoChildUser as CategoryData)
|
||||
}
|
||||
}.ignoreUnchanged()
|
||||
|
||||
private val categoryBlockingReasons: LiveData<Map<String, BlockingReason>?> = appLogic.deviceUserEntry.switchMap { deviceUser ->
|
||||
if (deviceUser?.type == UserType.Child) {
|
||||
appLogic.database.category().getCategoriesByChildId(deviceUser.id).switchMap { categories ->
|
||||
blockingReasonUtil.getCategoryBlockingReasons(
|
||||
childDisableLimitsUntil = liveDataFromValue(deviceUser.disableLimitsUntil),
|
||||
timeZone = liveDataFromValue(TimeZone.getTimeZone(deviceUser.timeZone)),
|
||||
categories = categories
|
||||
) as LiveData<Map<String, BlockingReason>?>
|
||||
}
|
||||
} else {
|
||||
liveDataFromValue(null as Map<String, BlockingReason>?)
|
||||
}
|
||||
}.ignoreUnchanged()
|
||||
|
||||
private val appsToBlock = categoryBlockingReasons.switchMap { blockingReasons ->
|
||||
if (blockingReasons == null) {
|
||||
liveDataFromValue(emptyList<String>())
|
||||
} else {
|
||||
categoryData.switchMap { categories ->
|
||||
when (categories) {
|
||||
is NoChildUser -> liveDataFromValue(emptyList<String>())
|
||||
is RealCategoryData -> {
|
||||
knownInstalledApps.switchMap { installedApps ->
|
||||
blockingAtActivityLevel.map { blockingAtActivityLevel ->
|
||||
val prepared = getAppsWithCategories(installedApps, categories, blockingAtActivityLevel)
|
||||
val result = mutableListOf<String>()
|
||||
|
||||
installedApps.forEach { packageName ->
|
||||
val appCategories = prepared[packageName] ?: emptySet()
|
||||
|
||||
if (appCategories.find { categoryId -> (blockingReasons[categoryId] ?: BlockingReason.None) == BlockingReason.None } == null) {
|
||||
result.add(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
} as LiveData<List<String>>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val realAppsToBlock = appLogic.database.config().isExperimentalFlagsSetAsync(ExperimentalFlags.SYSTEM_LEVEL_BLOCKING).switchMap { systemLevelBlocking ->
|
||||
if (systemLevelBlocking) {
|
||||
appsToBlock
|
||||
} else {
|
||||
liveDataFromValue(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAppsWithCategories(packageNames: List<String>, data: RealCategoryData, blockingAtActivityLevel: Boolean): Map<String, Set<String>> {
|
||||
val categoryForUnassignedApps = if (data.categories.find { it.id == data.categoryForUnassignedApps } != null) data.categoryForUnassignedApps else null
|
||||
|
||||
if (blockingAtActivityLevel) {
|
||||
val categoriesByPackageName = data.categoryApps.groupBy { it.packageNameWithoutActivityName }
|
||||
|
||||
val result = mutableMapOf<String, Set<String>>()
|
||||
|
||||
packageNames.forEach { packageName ->
|
||||
val categoriesItems = categoriesByPackageName[packageName]
|
||||
val categories = (categoriesItems?.map { it.categoryId }?.toSet() ?: emptySet()).toMutableSet()
|
||||
val isMainAppIncluded = categoriesItems?.find { !it.specifiesActivity } != null
|
||||
|
||||
if (!isMainAppIncluded) {
|
||||
if (categoryForUnassignedApps != null) {
|
||||
categories.add(categoryForUnassignedApps)
|
||||
}
|
||||
}
|
||||
|
||||
result[packageName] = categories
|
||||
}
|
||||
|
||||
return result
|
||||
} else {
|
||||
val categoryByPackageName = data.categoryApps.associateBy { it.packageName }
|
||||
|
||||
val result = mutableMapOf<String, Set<String>>()
|
||||
|
||||
packageNames.forEach { packageName ->
|
||||
val category = categoryByPackageName[packageName]?.categoryId ?: categoryForUnassignedApps
|
||||
|
||||
result[packageName] = if (category != null) setOf(category) else emptySet()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
realAppsToBlock.observeForever { appsToBlock ->
|
||||
appLogic.platformIntegration.stopSuspendingForAllApps()
|
||||
appLogic.platformIntegration.setSuspendedApps(appsToBlock, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CategoryData
|
||||
internal object NoChildUser: CategoryData()
|
||||
internal class RealCategoryData(
|
||||
val categoryForUnassignedApps: String,
|
||||
val categories: List<Category>,
|
||||
val categoryApps: List<CategoryApp>
|
||||
): CategoryData()
|
|
@ -391,9 +391,11 @@ object ApplyServerDataStatus {
|
|||
assignedAppsVersion = item.version
|
||||
)
|
||||
|
||||
if (thisDeviceUserCategoryIds.contains(item.categoryId)) {
|
||||
runAsync {
|
||||
platformIntegration.setSuspendedApps(item.assignedApps, false)
|
||||
if (!database.config().isExperimentalFlagsSetSync(ExperimentalFlags.SYSTEM_LEVEL_BLOCKING)) {
|
||||
if (thisDeviceUserCategoryIds.contains(item.categoryId)) {
|
||||
runAsync {
|
||||
platformIntegration.setSuspendedApps(item.assignedApps, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import io.timelimit.android.async.Threads
|
|||
import io.timelimit.android.coroutines.executeAndWait
|
||||
import io.timelimit.android.crypto.Sha512
|
||||
import io.timelimit.android.data.Database
|
||||
import io.timelimit.android.data.model.ExperimentalFlags
|
||||
import io.timelimit.android.data.model.PendingSyncAction
|
||||
import io.timelimit.android.data.model.PendingSyncActionType
|
||||
import io.timelimit.android.data.model.UserType
|
||||
|
@ -164,15 +165,17 @@ object ApplyActionUtil {
|
|||
LocalDatabaseParentActionDispatcher.dispatchParentActionSync(action, database)
|
||||
|
||||
// disable suspending the assigned app
|
||||
if (action is AddCategoryAppsAction) {
|
||||
val thisDeviceId = database.config().getOwnDeviceIdSync()!!
|
||||
val thisDeviceEntry = database.device().getDeviceByIdSync(thisDeviceId)!!
|
||||
if (!database.config().isExperimentalFlagsSetSync(ExperimentalFlags.SYSTEM_LEVEL_BLOCKING)) {
|
||||
if (action is AddCategoryAppsAction) {
|
||||
val thisDeviceId = database.config().getOwnDeviceIdSync()!!
|
||||
val thisDeviceEntry = database.device().getDeviceByIdSync(thisDeviceId)!!
|
||||
|
||||
if (thisDeviceEntry.currentUserId != "") {
|
||||
val userCategories = database.category().getCategoriesByChildIdSync(thisDeviceEntry.currentUserId)
|
||||
if (thisDeviceEntry.currentUserId != "") {
|
||||
val userCategories = database.category().getCategoriesByChildIdSync(thisDeviceEntry.currentUserId)
|
||||
|
||||
if (userCategories.find { category -> category.id == action.categoryId } != null) {
|
||||
platformIntegration.setSuspendedApps(action.packageNames, false)
|
||||
if (userCategories.find { category -> category.id == action.categoryId } != null) {
|
||||
platformIntegration.setSuspendedApps(action.packageNames, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class DiagnoseExperimentalFlagFragment : Fragment() {
|
|||
|
||||
checkboxes.forEach { binding.container.addView(it) }
|
||||
|
||||
database.config().getExperimentalFlagsLive().observe(this, Observer { setFlags ->
|
||||
database.config().experimentalFlags.observe(this, Observer { setFlags ->
|
||||
flags.forEachIndexed { index, flag ->
|
||||
val checkbox = checkboxes[index]
|
||||
val isFlagSet = (setFlags and flag.flag) == flag.flag
|
||||
|
@ -96,6 +96,11 @@ data class DiagnoseExperimentalFlagItem(
|
|||
label = R.string.diagnose_exf_lom,
|
||||
flag = ExperimentalFlags.DISABLE_BLOCK_ON_MANIPULATION,
|
||||
enable = !BuildConfig.storeCompilant
|
||||
),
|
||||
DiagnoseExperimentalFlagItem(
|
||||
label = R.string.diagnose_exf_slb,
|
||||
flag = ExperimentalFlags.SYSTEM_LEVEL_BLOCKING,
|
||||
enable = !BuildConfig.storeCompilant
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -54,4 +54,5 @@
|
|||
|
||||
<string name="diagnose_exf_title">Experimentelle Parameter</string>
|
||||
<string name="diagnose_exf_lom">Sperrung nach Manipulationen deaktivieren</string>
|
||||
<string name="diagnose_exf_slb">Apps auf Systemebene sperren</string>
|
||||
</resources>
|
||||
|
|
|
@ -54,4 +54,5 @@
|
|||
|
||||
<string name="diagnose_exf_title">Experimental flags</string>
|
||||
<string name="diagnose_exf_lom">Disable locking after manipulations</string>
|
||||
<string name="diagnose_exf_slb">Block Apps at system level</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue