DataControl v0.1.0 : contrôle du forfait data mobile via pare-feu VPN local

Surveillance de la consommation de données mobiles avec coupure automatique
en cas de dépassement de forfait, sans root ni impact sur le Wi-Fi.

- Pare-feu local (VpnService) actif uniquement sur données mobiles
- Liste blanche d'applications toujours autorisées
- Coupure cyclique totale après dépassement (intervalle paramétrable)
- Réglages complets (forfait, prix, date de début, reset auto/manuel)
- Estimation du coût total en temps réel
- Notification permanente colorée par état
- UI Compose Material 3

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
JohnnyandClaude Sonnet 5 committed 2026-07-02 18:37:45 +02:00
1 parent a71026898b
commit 536a981f9e
57 files changed
+2871

No files matched your search

@@ -0,0 +1,78 @@
package com.jttools.datacontrol.ui
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.net.VpnService
import android.os.Build
import android.os.PowerManager
import android.provider.Settings
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import com.jttools.datacontrol.service.FirewallVpnService
/**
* Regroupe les autorisations système nécessaires (VPN, notifications, batterie) pour que
* les écrans Compose puissent les demander sans dépendre directement de l'Activity.
*/
class SystemActions(private val activity: ComponentActivity) {
private var onVpnResult: ((Boolean) -> Unit)? = null
private var onNotificationResult: ((Boolean) -> Unit)? = null
private val vpnLauncher: ActivityResultLauncher<Intent> = activity.registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
onVpnResult?.invoke(result.resultCode == android.app.Activity.RESULT_OK)
}
private val notificationLauncher: ActivityResultLauncher<String> = activity.registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted -> onNotificationResult?.invoke(granted) }
fun isVpnPrepared(): Boolean = FirewallVpnService.isPrepared(activity)
fun requestVpnPermission(onResult: (Boolean) -> Unit) {
val intent = VpnService.prepare(activity)
if (intent == null) {
onResult(true)
} else {
onVpnResult = onResult
vpnLauncher.launch(intent)
}
}
fun hasNotificationPermission(): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return true
return ContextCompat.checkSelfPermission(
activity, android.Manifest.permission.POST_NOTIFICATIONS
) == android.content.pm.PackageManager.PERMISSION_GRANTED
}
fun requestNotificationPermission(onResult: (Boolean) -> Unit) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
onResult(true)
return
}
onNotificationResult = onResult
notificationLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
}
fun isIgnoringBatteryOptimizations(): Boolean {
val pm = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
return pm.isIgnoringBatteryOptimizations(activity.packageName)
}
@SuppressLint("BatteryLife")
fun requestIgnoreBatteryOptimizations() {
val intent = Intent(
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:${activity.packageName}")
)
activity.startActivity(intent)
}
}