- VPN retiré : le contrôle reste activé (alerte parent, tunnel remonté après 30 s, autorisation redemandée à l'ouverture) - Horloge de référence : changer date/heure/fuseau ne contourne plus les plages horaires ni le temps d'écran (signalé au parent) - Mot de passe : PBKDF2 + attente croissante après 3 échecs ; conversion automatique des anciens hachages - Écrans protégés : aucun affichage avant chargement des réglages ; effacement du journal protégé - Signature release via keystore.properties (même clé que les versions publiées) - Sauvegarde Google : réglages, appairage et journal exclus - Alerte admin fiable (goAsync), relance refusée signalée, liste d'applis renvoyée à chaque installation, code d'appairage consommé - Journal thread-safe et sans recopie à chaque ligne ; correctifs lint - Tests unitaires (mot de passe, règles, versions, config Firebase) ; README aligné sur le comportement réel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9CBCVP5oDu2sfoYPisNCQ
59 lines
2.4 KiB
Kotlin
59 lines
2.4 KiB
Kotlin
package com.jttools.datacontrol
|
|
|
|
import android.os.Bundle
|
|
import androidx.activity.ComponentActivity
|
|
import androidx.activity.compose.setContent
|
|
import androidx.activity.enableEdgeToEdge
|
|
import androidx.lifecycle.lifecycleScope
|
|
import com.jttools.datacontrol.data.SettingsRepository
|
|
import com.jttools.datacontrol.log.AppLog
|
|
import com.jttools.datacontrol.service.DataMonitorService
|
|
import com.jttools.datacontrol.ui.SystemActions
|
|
import com.jttools.datacontrol.ui.navigation.DataControlNavHost
|
|
import com.jttools.datacontrol.ui.theme.DataControlTheme
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
import kotlinx.coroutines.flow.first
|
|
import kotlinx.coroutines.launch
|
|
import javax.inject.Inject
|
|
|
|
@AndroidEntryPoint
|
|
class MainActivity : ComponentActivity() {
|
|
|
|
@Inject lateinit var settingsRepository: SettingsRepository
|
|
|
|
private lateinit var systemActions: SystemActions
|
|
private var vpnAskedThisSession = false
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
systemActions = SystemActions(this)
|
|
enableEdgeToEdge()
|
|
// Démarre le suivi de consommation dès l'ouverture de l'app, indépendamment du contrôle
|
|
// (pare-feu) : sans ça, le tableau de bord/les réglages restent à 0 tant que le contrôle
|
|
// n'a jamais été activé, car c'est ce service qui alimente MonitorStateHolder.
|
|
DataMonitorService.start(this)
|
|
setContent {
|
|
DataControlTheme {
|
|
DataControlNavHost(systemActions = systemActions)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
// Contrôle actif mais autorisation VPN perdue (retirée, ou prise par un autre VPN) :
|
|
// on la redemande à l'ouverture, une seule fois par session pour ne pas boucler.
|
|
if (vpnAskedThisSession) return
|
|
lifecycleScope.launch {
|
|
if (settingsRepository.settingsFlow.first().controlEnabled && !systemActions.isVpnPrepared()) {
|
|
vpnAskedThisSession = true
|
|
AppLog.w("Pare-feu", "Contrôle actif sans autorisation VPN : nouvelle demande")
|
|
systemActions.requestVpnPermission { granted ->
|
|
AppLog.i("Pare-feu", "Autorisation VPN ${if (granted) "rétablie" else "REFUSÉE"}")
|
|
if (granted) DataMonitorService.start(this@MainActivity)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|