mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 01:39:22 +02:00
Process network ids for the limit login categories
This commit is contained in:
parent
2f85752b97
commit
c1f79878fc
1 changed files with 109 additions and 20 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 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
|
||||
|
@ -23,25 +23,51 @@ import io.timelimit.android.data.extensions.getCategoryWithParentCategories
|
|||
import io.timelimit.android.data.model.ExperimentalFlags
|
||||
import io.timelimit.android.data.model.derived.CompleteUserLoginRelatedData
|
||||
import io.timelimit.android.integration.platform.BatteryStatus
|
||||
import io.timelimit.android.integration.platform.NetworkId
|
||||
import io.timelimit.android.livedata.ignoreUnchanged
|
||||
import io.timelimit.android.livedata.liveDataFromFunction
|
||||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.logic.BlockingReason
|
||||
import io.timelimit.android.logic.RealTime
|
||||
import io.timelimit.android.logic.blockingreason.CategoryHandlingCache
|
||||
import java.lang.IllegalStateException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
sealed class AllowUserLoginStatus {
|
||||
data class Allow(val maxTime: Long): AllowUserLoginStatus()
|
||||
data class ForbidByCategory(val categoryTitle: String, val blockingReason: BlockingReason, val maxTime: Long): AllowUserLoginStatus()
|
||||
open val dependsOnNetworkId = false
|
||||
|
||||
data class Allow(
|
||||
val maxTime: Long,
|
||||
override val dependsOnNetworkId: Boolean
|
||||
): AllowUserLoginStatus()
|
||||
|
||||
data class ForbidByCategory(
|
||||
val categoryTitle: String,
|
||||
val blockingReason: BlockingReason,
|
||||
val maxTime: Long,
|
||||
override val dependsOnNetworkId: Boolean
|
||||
): AllowUserLoginStatus()
|
||||
|
||||
object ForbidByMissingSync: AllowUserLoginStatus()
|
||||
object ForbidUserNotFound: AllowUserLoginStatus()
|
||||
}
|
||||
|
||||
object AllowUserLoginStatusUtil {
|
||||
private fun calculate(data: CompleteUserLoginRelatedData, time: RealTime, cache: CategoryHandlingCache, batteryStatus: BatteryStatus, missingSyncForLimitLoginUser: Boolean): AllowUserLoginStatus = synchronized(cache) {
|
||||
private fun calculate(
|
||||
data: CompleteUserLoginRelatedData,
|
||||
time: RealTime,
|
||||
cache: CategoryHandlingCache,
|
||||
batteryStatus: BatteryStatus,
|
||||
missingSyncForLimitLoginUser: Boolean,
|
||||
currentNetworkId: NetworkId?
|
||||
): AllowUserLoginStatus = synchronized(cache) {
|
||||
val hasPremium = data.deviceRelatedData.isConnectedAndHasPremium || data.deviceRelatedData.isLocalMode
|
||||
|
||||
if (!hasPremium) {
|
||||
return AllowUserLoginStatus.Allow(maxTime = Long.MAX_VALUE)
|
||||
return AllowUserLoginStatus.Allow(
|
||||
maxTime = Long.MAX_VALUE,
|
||||
dependsOnNetworkId = false
|
||||
)
|
||||
}
|
||||
|
||||
return if (data.limitLoginCategoryUserRelatedData != null && data.loginRelatedData.limitLoginCategory != null) {
|
||||
|
@ -52,6 +78,7 @@ object AllowUserLoginStatusUtil {
|
|||
val preBlockDuration = data.loginRelatedData.limitLoginCategory.preBlockDuration
|
||||
val maxCheckedTime = time.timeInMillis + preBlockDuration
|
||||
val categoryIds = data.limitLoginCategoryUserRelatedData.getCategoryWithParentCategories(data.loginRelatedData.limitLoginCategory.categoryId)
|
||||
var dependsOnAnyNetworkId = false
|
||||
|
||||
while (true) {
|
||||
cache.reportStatus(
|
||||
|
@ -60,18 +87,21 @@ object AllowUserLoginStatusUtil {
|
|||
timeInMillis = currentCheckedTime,
|
||||
shouldTrustTimeTemporarily = time.shouldTrustTimeTemporarily,
|
||||
batteryStatus = batteryStatus,
|
||||
currentNetworkId = null, // only checks shouldBlockAtSystemLevel which ignores the network id
|
||||
currentNetworkId = currentNetworkId,
|
||||
hasPremiumOrLocalMode = data.deviceRelatedData.isLocalMode || data.deviceRelatedData.isConnectedAndHasPremium
|
||||
)
|
||||
|
||||
val handlings = categoryIds.map { cache.get(it) }
|
||||
val remainingTimeToCheck = maxCheckedTime - currentCheckedTime
|
||||
|
||||
dependsOnAnyNetworkId = dependsOnAnyNetworkId or (handlings.find { it.dependsOnNetworkId } != null)
|
||||
|
||||
handlings.find { it.remainingSessionDuration != null && it.remainingSessionDuration < remainingTimeToCheck }?.let { blockingHandling ->
|
||||
return AllowUserLoginStatus.ForbidByCategory(
|
||||
categoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title,
|
||||
blockingReason = BlockingReason.SessionDurationLimit,
|
||||
maxTime = blockingHandling.dependsOnMaxTime
|
||||
maxTime = blockingHandling.dependsOnMaxTime,
|
||||
dependsOnNetworkId = dependsOnAnyNetworkId
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -79,7 +109,8 @@ object AllowUserLoginStatusUtil {
|
|||
return AllowUserLoginStatus.ForbidByCategory(
|
||||
categoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title,
|
||||
blockingReason = BlockingReason.TimeOver,
|
||||
maxTime = blockingHandling.dependsOnMaxTime
|
||||
maxTime = blockingHandling.dependsOnMaxTime,
|
||||
dependsOnNetworkId = dependsOnAnyNetworkId
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -87,7 +118,19 @@ object AllowUserLoginStatusUtil {
|
|||
return AllowUserLoginStatus.ForbidByCategory(
|
||||
categoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title,
|
||||
blockingReason = blockingHandling.systemLevelBlockingReason,
|
||||
maxTime = blockingHandling.dependsOnMaxTime
|
||||
maxTime = blockingHandling.dependsOnMaxTime,
|
||||
dependsOnNetworkId = dependsOnAnyNetworkId
|
||||
)
|
||||
}
|
||||
|
||||
handlings.find { !it.okByNetworkId }?.let { blockingHandling ->
|
||||
if (!dependsOnAnyNetworkId) throw IllegalStateException()
|
||||
|
||||
return AllowUserLoginStatus.ForbidByCategory(
|
||||
categoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title,
|
||||
blockingReason = blockingHandling.activityBlockingReason,
|
||||
maxTime = Long.MAX_VALUE,
|
||||
dependsOnNetworkId = dependsOnAnyNetworkId
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -101,12 +144,14 @@ object AllowUserLoginStatusUtil {
|
|||
val maxTimeByCategories = categoryIds.map { cache.get(it) }.minByOrNull { it.dependsOnMaxTime }?.dependsOnMaxTime ?: Long.MAX_VALUE
|
||||
|
||||
AllowUserLoginStatus.Allow(
|
||||
maxTime = (maxTimeByCategories - preBlockDuration).coerceAtLeast(time.timeInMillis + 1000)
|
||||
maxTime = (maxTimeByCategories - preBlockDuration).coerceAtLeast(time.timeInMillis + 1000),
|
||||
dependsOnNetworkId = dependsOnAnyNetworkId
|
||||
)
|
||||
}
|
||||
} else {
|
||||
AllowUserLoginStatus.Allow(
|
||||
maxTime = Long.MAX_VALUE
|
||||
maxTime = Long.MAX_VALUE,
|
||||
dependsOnNetworkId = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -118,27 +163,54 @@ object AllowUserLoginStatusUtil {
|
|||
val userRelatedData = logic.database.derivedDataDao().getUserLoginRelatedDataSync(userId) ?: return AllowUserLoginStatus.ForbidUserNotFound
|
||||
val realTime = RealTime.newInstance()
|
||||
val batteryStatus = logic.platformIntegration.getBatteryStatus()
|
||||
val latch = CountDownLatch(1)
|
||||
|
||||
Threads.mainThreadHandler.post {
|
||||
logic.realTimeLogic.getRealTime(realTime)
|
||||
latch.countDown()
|
||||
CountDownLatch(1).let { latch ->
|
||||
Threads.mainThreadHandler.post {
|
||||
logic.realTimeLogic.getRealTime(realTime)
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
latch.await()
|
||||
}
|
||||
|
||||
latch.await()
|
||||
val attempt1 = calculate(
|
||||
data = userRelatedData,
|
||||
batteryStatus = batteryStatus,
|
||||
time = realTime,
|
||||
cache = CategoryHandlingCache(),
|
||||
missingSyncForLimitLoginUser = requireSyncOnLimitLoginUser && !didSync,
|
||||
currentNetworkId = null
|
||||
)
|
||||
|
||||
return calculate(
|
||||
return if (attempt1.dependsOnNetworkId) {
|
||||
val currentNetworkId = CountDownLatch(1).let { latch ->
|
||||
var currentNetworkId: NetworkId? = null
|
||||
|
||||
Threads.mainThreadHandler.post {
|
||||
currentNetworkId = logic.platformIntegration.getCurrentNetworkId()
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
latch.await()
|
||||
|
||||
currentNetworkId!!
|
||||
}
|
||||
|
||||
calculate(
|
||||
data = userRelatedData,
|
||||
batteryStatus = batteryStatus,
|
||||
time = realTime,
|
||||
cache = CategoryHandlingCache(),
|
||||
missingSyncForLimitLoginUser = requireSyncOnLimitLoginUser && !didSync
|
||||
)
|
||||
missingSyncForLimitLoginUser = requireSyncOnLimitLoginUser && !didSync,
|
||||
currentNetworkId = currentNetworkId
|
||||
)
|
||||
} else attempt1
|
||||
}
|
||||
|
||||
fun calculateLive(logic: AppLogic, userId: String, didSyncLive: LiveData<Boolean>): LiveData<AllowUserLoginStatus> = object : MediatorLiveData<AllowUserLoginStatus>() {
|
||||
val cache = CategoryHandlingCache()
|
||||
val time = RealTime.newInstance()
|
||||
val currentNetworkIdLive = liveDataFromFunction { logic.platformIntegration.getCurrentNetworkId() }.ignoreUnchanged()
|
||||
var batteryStatus: BatteryStatus? = null
|
||||
var hasUserLoginRelatedData = false
|
||||
var userLoginRelatedData: CompleteUserLoginRelatedData? = null
|
||||
|
@ -147,6 +219,8 @@ object AllowUserLoginStatusUtil {
|
|||
var isConnectedMode = false
|
||||
var didLoadIsConnectedMode = false
|
||||
var didSync = false
|
||||
var isObservingNetworkId = false
|
||||
var currentNetworkId: NetworkId? = null
|
||||
|
||||
init {
|
||||
addSource(logic.platformIntegration.getBatteryStatusLive(), androidx.lifecycle.Observer {
|
||||
|
@ -194,7 +268,8 @@ object AllowUserLoginStatusUtil {
|
|||
batteryStatus = batteryStatus,
|
||||
cache = cache,
|
||||
time = time,
|
||||
missingSyncForLimitLoginUser = isConnectedMode && requireSyncForLimitLoginUsers && !didSync
|
||||
missingSyncForLimitLoginUser = isConnectedMode && requireSyncForLimitLoginUsers && !didSync,
|
||||
currentNetworkId = currentNetworkId
|
||||
)
|
||||
|
||||
if (result != value) {
|
||||
|
@ -212,6 +287,20 @@ object AllowUserLoginStatusUtil {
|
|||
logic.timeApi.cancelScheduledAction(updateRunnable)
|
||||
logic.timeApi.runDelayedByUptime(updateRunnable, scheduledTime - time.timeInMillis)
|
||||
}
|
||||
|
||||
if (result.dependsOnNetworkId != isObservingNetworkId) {
|
||||
// important detail: the addSource can call update immediately
|
||||
isObservingNetworkId = result.dependsOnNetworkId
|
||||
|
||||
if (result.dependsOnNetworkId) {
|
||||
addSource(currentNetworkIdLive) {
|
||||
currentNetworkId = it; update()
|
||||
}
|
||||
} else {
|
||||
removeSource(currentNetworkIdLive)
|
||||
currentNetworkId = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActive() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue